Danilo Krummrich, Red Hat
rust: pci: implement I/O mappable `pci::Bar`
rust: pci: add basic PCI device / driver abstractions
rust: add devres abstraction
rust: add `io::Io` base type
rust: add `dev_*` print macros.
rust: add `Revocable` type
rust: add rcu abstraction
rust: implement `IdArray`, `IdTable` and `RawDeviceId`
rust: implement generic driver registration
rust: pass module name to `Module::init`
--
rust: introduce `InPlaceModule`
rust: init: introduce `Opaque::try_ffi_init`
samples/rust/rust_pci_driver/[driver.rs, mod.{c, rs}]
samples/rust/rust_pci_sample/mod.c
// SPDX-License-Identifier: GPL-2.0 #include <linux/module.h> #include <linux/pci.h> #define PCI_DEVICE_ID_REDHAT_QEMU_PCI_TESTDEV 0x0005 extern int rust_pci_driver_probe(struct pci_dev *dev, const struct pci_device_id *id); extern void rust_pci_driver_remove(struct pci_dev *dev); static const struct pci_device_id rust_pci_driver_ids[] = { { PCI_DEVICE(PCI_VENDOR_ID_REDHAT, PCI_DEVICE_ID_REDHAT_QEMU_PCI_TESTDEV) }, {} }; static struct pci_driver rust_pci_driver = { .name = "rust_pci_driver_sample", .id_table = rust_pci_driver_ids, .probe = rust_pci_driver_probe, .remove = rust_pci_driver_remove, }; static int __init rust_pci_driver_init(void) { return pci_register_driver(&rust_pci_driver); } static void __exit rust_pci_driver_exit(void) { pci_unregister_driver(&rust_pci_driver); } module_init(rust_pci_driver_init); module_exit(rust_pci_driver_exit); MODULE_AUTHOR("Danilo Krummrich"); MODULE_DESCRIPTION("Rust PCI driver sample"); MODULE_LICENSE("GPL v2");
// SPDX-License-Identifier: GPL-2.0 #include <linux/module.h> #include <linux/pci.h> #define PCI_DEVICE_ID_REDHAT_QEMU_PCI_TESTDEV 0x0005 extern int rust_pci_driver_probe(struct pci_dev *dev, const struct pci_device_id *id); extern void rust_pci_driver_remove(struct pci_dev *dev); static const struct pci_device_id rust_pci_driver_ids[] = { { PCI_DEVICE(PCI_VENDOR_ID_REDHAT, PCI_DEVICE_ID_REDHAT_QEMU_PCI_TESTDEV) }, {} }; static struct pci_driver rust_pci_driver = { .name = "rust_pci_driver_sample", .id_table = rust_pci_driver_ids, .probe = rust_pci_driver_probe, .remove = rust_pci_driver_remove, }; static int __init rust_pci_driver_init(void) { return pci_register_driver(&rust_pci_driver); } static void __exit rust_pci_driver_exit(void) { pci_unregister_driver(&rust_pci_driver); } module_init(rust_pci_driver_init); module_exit(rust_pci_driver_exit); MODULE_AUTHOR("Danilo Krummrich"); MODULE_DESCRIPTION("Rust PCI driver sample"); MODULE_LICENSE("GPL v2");
samples/rust/rust_pci_sample/driver.rs
// SPDX-License-Identifier: GPL-2.0 //! Rust PCI driver sample use kernel::{bindings, prelude::*}; const __LOG_PREFIX: &[u8] = b"rust_pci_driver_sample\0"; #[no_mangle] unsafe extern "C" fn rust_pci_driver_probe( _pdev: *mut bindings::pci_dev, _ent: bindings::pci_device_id, ) -> core::ffi::c_int { pr_info!("Probe Rust PCI driver sample.\n"); 0 } #[no_mangle] unsafe extern "C" fn rust_pci_driver_remove(_pdev: *mut bindings::pci_dev) { pr_info!("Remove Rust PCI driver sample.\n"); }
// SPDX-License-Identifier: GPL-2.0 //! Rust PCI driver sample use kernel::{bindings, prelude::*}; const __LOG_PREFIX: &[u8] = b"rust_pci_driver_sample\0"; #[no_mangle] unsafe extern "C" fn rust_pci_driver_probe( _pdev: *mut bindings::pci_dev, _ent: bindings::pci_device_id, ) -> core::ffi::c_int { pr_info!("Probe Rust PCI driver sample.\n"); 0 } #[no_mangle] unsafe extern "C" fn rust_pci_driver_remove(_pdev: *mut bindings::pci_dev) { pr_info!("Remove Rust PCI driver sample.\n"); }
__LOG_PREFIX
manuallyprobe()
, remove()
, suspend()
, resume()
, etc.)kmem_cache
, debug structures, etc.)samples/rust/rust_pci_sample/mod.rs
// SPDX-License-Identifier: GPL-2.0 //! Rust PCI driver sample. mod driver; use core::ptr; use kernel::{bindings, error::to_result, prelude::*}; module! { type: Module, name: "rust_pci_driver_sample", author: "Danilo Krummrich", description: "Rust PCI driver sample", license: "GPL", } struct Module; impl kernel::Module for Module { fn init(name: &'static CStr, module: &'static ThisModule) -> Result<Self> { // SAFETY: `driver::DRIVER` is a valid `struct pci_driver`; `ThisModule` //is equivalent to C's `THIS_MODULE` and hence valid for // `__pci_register_driver`. `name` is passed as `NULL` terminated C // string. // // Returns zero when the driver was registered successfully, a non-zero // error code otherwise, which is handled by `to_result`. to_result(unsafe { bindings::__pci_register_driver( ptr::addr_of_mut!(driver::DRIVER), module.as_ptr(), name.as_char_ptr(), ) })?; Ok(Module) } } impl Drop for Module { fn drop(&mut self) { // SAFETY: `Module::drop` is only ever called when `driver::DRIVER` was // registered successfully. unsafe { bindings::pci_unregister_driver(ptr::addr_of_mut!(driver::DRIVER)) }; } }
// SPDX-License-Identifier: GPL-2.0 //! Rust PCI driver sample. mod driver; use core::ptr; use kernel::{bindings, error::to_result, prelude::*}; module! { type: Module, name: "rust_pci_driver_sample", author: "Danilo Krummrich", description: "Rust PCI driver sample", license: "GPL", } struct Module; impl kernel::Module for Module { fn init(name: &'static CStr, module: &'static ThisModule) -> Result<Self> { // SAFETY: `driver::DRIVER` is a valid `struct pci_driver`; `ThisModule` //is equivalent to C's `THIS_MODULE` and hence valid for // `__pci_register_driver`. `name` is passed as `NULL` terminated C // string. // // Returns zero when the driver was registered successfully, a non-zero // error code otherwise, which is handled by `to_result`. to_result(unsafe { bindings::__pci_register_driver( ptr::addr_of_mut!(driver::DRIVER), module.as_ptr(), name.as_char_ptr(), ) })?; Ok(Module) } } impl Drop for Module { fn drop(&mut self) { // SAFETY: `Module::drop` is only ever called when `driver::DRIVER` was // registered successfully. unsafe { bindings::pci_unregister_driver(ptr::addr_of_mut!(driver::DRIVER)) }; } }
samples/rust/rust_pci_sample/driver.rs
// SPDX-License-Identifier: GPL-2.0 //! Rust PCI driver sample use kernel::{bindings, c_str, prelude::*}; const PCI_DEVICE_ID_REDHAT_QEMU_PCI_TESTDEV: u32 = 0x0005; pub(crate) static mut DRIVER: bindings::pci_driver = Driver::driver(); struct Driver; impl Driver { const IDS: usize = 2; const __ID_TABLE: [bindings::pci_device_id; Self::IDS] = Self::id_table(); const fn driver() -> bindings::pci_driver { // SAFETY: `bindings::pci_driver` is valid to be zero initialized. let mut drv: bindings::pci_driver = unsafe { core::mem::zeroed() }; drv.name = c_str!("rust_pci_driver_sample").as_char_ptr(); drv.id_table = Self::__ID_TABLE.as_ptr(); drv.probe = Some(Self::probe); drv.remove = Some(Self::remove); drv } const fn id_table() -> [bindings::pci_device_id; 2] { // SAFETY: `bindings::pci_device_id` is valid to be zero initialized. let mut id: bindings::pci_device_id = unsafe { core::mem::zeroed() }; id.vendor = bindings::PCI_VENDOR_ID_REDHAT; id.device = PCI_DEVICE_ID_REDHAT_QEMU_PCI_TESTDEV; id.subvendor = bindings::PCI_ANY_ID as u32; id.subdevice = bindings::PCI_ANY_ID as u32; // SAFETY: `bindings::pci_device_id` is valid to be zero initialized. let sentinel: bindings::pci_device_id = unsafe { core::mem::zeroed() }; [id, sentinel] } extern "C" fn probe( _pdev: *mut bindings::pci_dev, _ent: *const bindings::pci_device_id, ) -> core::ffi::c_int { pr_info!("Probe Rust PCI driver sample.\n"); 0 } extern "C" fn remove(_pdev: *mut bindings::pci_dev) { pr_info!("Remove Rust PCI driver sample.\n"); } }
// SPDX-License-Identifier: GPL-2.0 //! Rust PCI driver sample use kernel::{bindings, c_str, prelude::*}; const PCI_DEVICE_ID_REDHAT_QEMU_PCI_TESTDEV: u32 = 0x0005; pub(crate) static mut DRIVER: bindings::pci_driver = Driver::driver(); struct Driver; impl Driver { const IDS: usize = 2; const __ID_TABLE: [bindings::pci_device_id; Self::IDS] = Self::id_table(); const fn driver() -> bindings::pci_driver { // SAFETY: `bindings::pci_driver` is valid to be zero initialized. let mut drv: bindings::pci_driver = unsafe { core::mem::zeroed() }; drv.name = c_str!("rust_pci_driver_sample").as_char_ptr(); drv.id_table = Self::__ID_TABLE.as_ptr(); drv.probe = Some(Self::probe); drv.remove = Some(Self::remove); drv } const fn id_table() -> [bindings::pci_device_id; 2] { // SAFETY: `bindings::pci_device_id` is valid to be zero initialized. let mut id: bindings::pci_device_id = unsafe { core::mem::zeroed() }; id.vendor = bindings::PCI_VENDOR_ID_REDHAT; id.device = PCI_DEVICE_ID_REDHAT_QEMU_PCI_TESTDEV; id.subvendor = bindings::PCI_ANY_ID as u32; id.subdevice = bindings::PCI_ANY_ID as u32; // SAFETY: `bindings::pci_device_id` is valid to be zero initialized. let sentinel: bindings::pci_device_id = unsafe { core::mem::zeroed() }; [id, sentinel] } extern "C" fn probe( _pdev: *mut bindings::pci_dev, _ent: *const bindings::pci_device_id, ) -> core::ffi::c_int { pr_info!("Probe Rust PCI driver sample.\n"); 0 } extern "C" fn remove(_pdev: *mut bindings::pci_dev) { pr_info!("Remove Rust PCI driver sample.\n"); } }
__pci_register_driver()
, pci_unregister_driver()
)rust/kernel/pci.rs
// SPDX-License-Identifier: GPL-2.0 //! Wrappers for the PCI subsystem //! //! C header: [`include/linux/pci.h`](srctree/include/linux/pci.h) use core::cell::UnsafeCell; use core::marker::PhantomData; use kernel::{ alloc::flags::*, bindings, error::{from_result, to_result}, prelude::*, }; /// Drivers must implement this trait to register a PCI driver. pub trait Driver { /// Pointer to the PCI driver's ID table. /// /// This is highly unsafe, since we have to trust the driver, that the provided pointer is /// valid. const ID_TABLE: *const bindings::pci_device_id; /// PCI driver probe. /// /// Called when a PCI device is matched against a PCI driver. fn probe(pdev: *mut bindings::pci_dev) -> Result; /// PCI driver remove. /// /// Called when the PCI device is unbound. fn remove(pdev: *mut bindings::pci_dev); } struct Adapter<T: Driver>(PhantomData<T>); impl<T> Adapter<T> where T: Driver, { extern "C" fn probe( pdev: *mut bindings::pci_dev, _ent: *const bindings::pci_device_id, ) -> core::ffi::c_int { from_result(|| { T::probe(pdev)?; Ok(0) }) } extern "C" fn remove(pdev: *mut bindings::pci_dev) { T::remove(pdev); } } /// Registration structure for a PCI driver. /// /// The existance of an instance of this structure implies that the corresponding PCI driver is /// currently registered. pub struct Registration<T: Driver> { driver: Pin<KBox<UnsafeCell<bindings::pci_driver>>>, _p: PhantomData<T>, } impl<T> Registration<T> where T: Driver, { /// Register a new PCI driver from `T: Driver`. pub fn new(name: &'static CStr, module: &'static ThisModule) -> Result<Self> { let mut driver = KBox::pin(UnsafeCell::new(bindings::pci_driver::default()), GFP_KERNEL)?; // Abuse that `bindings::pci_driver` is `Unpin`. let inner = driver.get_mut(); inner.name = name.as_char_ptr(); inner.probe = Some(Adapter::<T>::probe); inner.remove = Some(Adapter::<T>::remove); inner.id_table = T::ID_TABLE; // SAFETY: `driver` is a valid `struct pci_driver`; `ThisModule` is equivalent to // C's `THIS_MODULE` and hence valid for `__pci_register_driver`. `name` is passed as `NULL` // terminated C string. // // Returns zero when the driver was registered successfully, a non-zero error code // otherwise, which is handled by `to_result`. to_result(unsafe { bindings::__pci_register_driver(driver.get(), module.as_ptr(), name.as_char_ptr()) })?; Ok(Self { driver, _p: PhantomData::<T>, }) } } impl<T> Drop for Registration<T> where T: Driver, { fn drop(&mut self) { // SAFETY: `Module::drop` is only ever called when `self.drv` was registered // successfully. unsafe { bindings::pci_unregister_driver(self.driver.get()) }; } } // SAFETY: `Registration` has no fields or methods accessible via `&Registration`, so it is safe to // share references to it with multiple threads as nothing can be done. unsafe impl<T> Sync for Registration<T> where T: Driver {} // SAFETY: Both registration and unregistration are implemented in C and safe to be performed from // any thread, so `Registration` is `Send`. unsafe impl<T> Send for Registration<T> where T: Driver {}
// SPDX-License-Identifier: GPL-2.0 //! Wrappers for the PCI subsystem //! //! C header: [`include/linux/pci.h`](srctree/include/linux/pci.h) use core::cell::UnsafeCell; use core::marker::PhantomData; use kernel::{ alloc::flags::*, bindings, error::{from_result, to_result}, prelude::*, }; /// Drivers must implement this trait to register a PCI driver. pub trait Driver { /// Pointer to the PCI driver's ID table. /// /// This is highly unsafe, since we have to trust the driver, that the provided pointer is /// valid. const ID_TABLE: *const bindings::pci_device_id; /// PCI driver probe. /// /// Called when a PCI device is matched against a PCI driver. fn probe(pdev: *mut bindings::pci_dev) -> Result; /// PCI driver remove. /// /// Called when the PCI device is unbound. fn remove(pdev: *mut bindings::pci_dev); } struct Adapter<T: Driver>(PhantomData<T>); impl<T> Adapter<T> where T: Driver, { extern "C" fn probe( pdev: *mut bindings::pci_dev, _ent: *const bindings::pci_device_id, ) -> core::ffi::c_int { from_result(|| { T::probe(pdev)?; Ok(0) }) } extern "C" fn remove(pdev: *mut bindings::pci_dev) { T::remove(pdev); } } /// Registration structure for a PCI driver. /// /// The existance of an instance of this structure implies that the corresponding PCI driver is /// currently registered. pub struct Registration<T: Driver> { driver: Pin<KBox<UnsafeCell<bindings::pci_driver>>>, _p: PhantomData<T>, } impl<T> Registration<T> where T: Driver, { /// Register a new PCI driver from `T: Driver`. pub fn new(name: &'static CStr, module: &'static ThisModule) -> Result<Self> { let mut driver = KBox::pin(UnsafeCell::new(bindings::pci_driver::default()), GFP_KERNEL)?; // Abuse that `bindings::pci_driver` is `Unpin`. let inner = driver.get_mut(); inner.name = name.as_char_ptr(); inner.probe = Some(Adapter::<T>::probe); inner.remove = Some(Adapter::<T>::remove); inner.id_table = T::ID_TABLE; // SAFETY: `driver` is a valid `struct pci_driver`; `ThisModule` is equivalent to // C's `THIS_MODULE` and hence valid for `__pci_register_driver`. `name` is passed as `NULL` // terminated C string. // // Returns zero when the driver was registered successfully, a non-zero error code // otherwise, which is handled by `to_result`. to_result(unsafe { bindings::__pci_register_driver(driver.get(), module.as_ptr(), name.as_char_ptr()) })?; Ok(Self { driver, _p: PhantomData::<T>, }) } } impl<T> Drop for Registration<T> where T: Driver, { fn drop(&mut self) { // SAFETY: `Module::drop` is only ever called when `self.drv` was registered // successfully. unsafe { bindings::pci_unregister_driver(self.driver.get()) }; } } // SAFETY: `Registration` has no fields or methods accessible via `&Registration`, so it is safe to // share references to it with multiple threads as nothing can be done. unsafe impl<T> Sync for Registration<T> where T: Driver {} // SAFETY: Both registration and unregistration are implemented in C and safe to be performed from // any thread, so `Registration` is `Send`. unsafe impl<T> Send for Registration<T> where T: Driver {}
// SPDX-License-Identifier: GPL-2.0 //! Wrappers for the PCI subsystem //! //! C header: [`include/linux/pci.h`](srctree/include/linux/pci.h) use core::cell::UnsafeCell; use core::marker::PhantomData; use kernel::{ alloc::flags::*, bindings, error::{from_result, to_result}, prelude::*, }; /// Drivers must implement this trait to register a PCI driver. pub trait Driver { /// Pointer to the PCI driver's ID table. /// /// This is highly unsafe, since we have to trust the driver, that the provided pointer is /// valid. const ID_TABLE: *const bindings::pci_device_id; /// PCI driver probe. /// /// Called when a PCI device is matched against a PCI driver. fn probe(pdev: *mut bindings::pci_dev) -> Result; /// PCI driver remove. /// /// Called when the PCI device is unbound. fn remove(pdev: *mut bindings::pci_dev); } struct Adapter<T: Driver>(PhantomData<T>); impl<T> Adapter<T> where T: Driver, { extern "C" fn probe( pdev: *mut bindings::pci_dev, _ent: *const bindings::pci_device_id, ) -> core::ffi::c_int { from_result(|| { T::probe(pdev)?; Ok(0) }) } extern "C" fn remove(pdev: *mut bindings::pci_dev) { T::remove(pdev); } } /// Registration structure for a PCI driver. /// /// The existance of an instance of this structure implies that the corresponding PCI driver is /// currently registered. pub struct Registration<T: Driver> { driver: Pin<KBox<UnsafeCell<bindings::pci_driver>>>, _p: PhantomData<T>, } impl<T> Registration<T> where T: Driver, { /// Register a new PCI driver from `T: Driver`. pub fn new(name: &'static CStr, module: &'static ThisModule) -> Result<Self> { let mut driver = KBox::pin(UnsafeCell::new(bindings::pci_driver::default()), GFP_KERNEL)?; // Abuse that `bindings::pci_driver` is `Unpin`. let inner = driver.get_mut(); inner.name = name.as_char_ptr(); inner.probe = Some(Adapter::<T>::probe); inner.remove = Some(Adapter::<T>::remove); inner.id_table = T::ID_TABLE; // SAFETY: `driver` is a valid `struct pci_driver`; `ThisModule` is equivalent to // C's `THIS_MODULE` and hence valid for `__pci_register_driver`. `name` is passed as `NULL` // terminated C string. // // Returns zero when the driver was registered successfully, a non-zero error code // otherwise, which is handled by `to_result`. to_result(unsafe { bindings::__pci_register_driver(driver.get(), module.as_ptr(), name.as_char_ptr()) })?; Ok(Self { driver, _p: PhantomData::<T>, }) } } impl<T> Drop for Registration<T> where T: Driver, { fn drop(&mut self) { // SAFETY: `Module::drop` is only ever called when `self.drv` was registered // successfully. unsafe { bindings::pci_unregister_driver(self.driver.get()) }; } } // SAFETY: `Registration` has no fields or methods accessible via `&Registration`, so it is safe to // share references to it with multiple threads as nothing can be done. unsafe impl<T> Sync for Registration<T> where T: Driver {} // SAFETY: Both registration and unregistration are implemented in C and safe to be performed from // any thread, so `Registration` is `Send`. unsafe impl<T> Send for Registration<T> where T: Driver {}
// SPDX-License-Identifier: GPL-2.0 //! Wrappers for the PCI subsystem //! //! C header: [`include/linux/pci.h`](srctree/include/linux/pci.h) use core::cell::UnsafeCell; use core::marker::PhantomData; use kernel::{ alloc::flags::*, bindings, error::{from_result, to_result}, prelude::*, }; /// Drivers must implement this trait to register a PCI driver. pub trait Driver { /// Pointer to the PCI driver's ID table. /// /// This is highly unsafe, since we have to trust the driver, that the provided pointer is /// valid. const ID_TABLE: *const bindings::pci_device_id; /// PCI driver probe. /// /// Called when a PCI device is matched against a PCI driver. fn probe(pdev: *mut bindings::pci_dev) -> Result; /// PCI driver remove. /// /// Called when the PCI device is unbound. fn remove(pdev: *mut bindings::pci_dev); } struct Adapter<T: Driver>(PhantomData<T>); impl<T> Adapter<T> where T: Driver, { extern "C" fn probe( pdev: *mut bindings::pci_dev, _ent: *const bindings::pci_device_id, ) -> core::ffi::c_int { from_result(|| { T::probe(pdev)?; Ok(0) }) } extern "C" fn remove(pdev: *mut bindings::pci_dev) { T::remove(pdev); } } /// Registration structure for a PCI driver. /// /// The existance of an instance of this structure implies that the corresponding PCI driver is /// currently registered. pub struct Registration<T: Driver> { driver: Pin<KBox<UnsafeCell<bindings::pci_driver>>>, _p: PhantomData<T>, } impl<T> Registration<T> where T: Driver, { /// Register a new PCI driver from `T: Driver`. pub fn new(name: &'static CStr, module: &'static ThisModule) -> Result<Self> { let mut driver = KBox::pin(UnsafeCell::new(bindings::pci_driver::default()), GFP_KERNEL)?; // Abuse that `bindings::pci_driver` is `Unpin`. let inner = driver.get_mut(); inner.name = name.as_char_ptr(); inner.probe = Some(Adapter::<T>::probe); inner.remove = Some(Adapter::<T>::remove); inner.id_table = T::ID_TABLE; // SAFETY: `driver` is a valid `struct pci_driver`; `ThisModule` is equivalent to // C's `THIS_MODULE` and hence valid for `__pci_register_driver`. `name` is passed as `NULL` // terminated C string. // // Returns zero when the driver was registered successfully, a non-zero error code // otherwise, which is handled by `to_result`. to_result(unsafe { bindings::__pci_register_driver(driver.get(), module.as_ptr(), name.as_char_ptr()) })?; Ok(Self { driver, _p: PhantomData::<T>, }) } } impl<T> Drop for Registration<T> where T: Driver, { fn drop(&mut self) { // SAFETY: `Module::drop` is only ever called when `self.drv` was registered // successfully. unsafe { bindings::pci_unregister_driver(self.driver.get()) }; } } // SAFETY: `Registration` has no fields or methods accessible via `&Registration`, so it is safe to // share references to it with multiple threads as nothing can be done. unsafe impl<T> Sync for Registration<T> where T: Driver {} // SAFETY: Both registration and unregistration are implemented in C and safe to be performed from // any thread, so `Registration` is `Send`. unsafe impl<T> Send for Registration<T> where T: Driver {}
// SPDX-License-Identifier: GPL-2.0 //! Wrappers for the PCI subsystem //! //! C header: [`include/linux/pci.h`](srctree/include/linux/pci.h) use core::cell::UnsafeCell; use core::marker::PhantomData; use kernel::{ alloc::flags::*, bindings, error::{from_result, to_result}, prelude::*, }; /// Drivers must implement this trait to register a PCI driver. pub trait Driver { /// Pointer to the PCI driver's ID table. /// /// This is highly unsafe, since we have to trust the driver, that the provided pointer is /// valid. const ID_TABLE: *const bindings::pci_device_id; /// PCI driver probe. /// /// Called when a PCI device is matched against a PCI driver. fn probe(pdev: *mut bindings::pci_dev) -> Result; /// PCI driver remove. /// /// Called when the PCI device is unbound. fn remove(pdev: *mut bindings::pci_dev); } struct Adapter<T: Driver>(PhantomData<T>); impl<T> Adapter<T> where T: Driver, { extern "C" fn probe( pdev: *mut bindings::pci_dev, _ent: *const bindings::pci_device_id, ) -> core::ffi::c_int { from_result(|| { T::probe(pdev)?; Ok(0) }) } extern "C" fn remove(pdev: *mut bindings::pci_dev) { T::remove(pdev); } } /// Registration structure for a PCI driver. /// /// The existance of an instance of this structure implies that the corresponding PCI driver is /// currently registered. pub struct Registration<T: Driver> { driver: Pin<KBox<UnsafeCell<bindings::pci_driver>>>, _p: PhantomData<T>, } impl<T> Registration<T> where T: Driver, { /// Register a new PCI driver from `T: Driver`. pub fn new(name: &'static CStr, module: &'static ThisModule) -> Result<Self> { let mut driver = KBox::pin(UnsafeCell::new(bindings::pci_driver::default()), GFP_KERNEL)?; // Abuse that `bindings::pci_driver` is `Unpin`. let inner = driver.get_mut(); inner.name = name.as_char_ptr(); inner.probe = Some(Adapter::<T>::probe); inner.remove = Some(Adapter::<T>::remove); inner.id_table = T::ID_TABLE; // SAFETY: `driver` is a valid `struct pci_driver`; `ThisModule` is equivalent to // C's `THIS_MODULE` and hence valid for `__pci_register_driver`. `name` is passed as `NULL` // terminated C string. // // Returns zero when the driver was registered successfully, a non-zero error code // otherwise, which is handled by `to_result`. to_result(unsafe { bindings::__pci_register_driver(driver.get(), module.as_ptr(), name.as_char_ptr()) })?; Ok(Self { driver, _p: PhantomData::<T>, }) } } impl<T> Drop for Registration<T> where T: Driver, { fn drop(&mut self) { // SAFETY: `Module::drop` is only ever called when `self.drv` was registered // successfully. unsafe { bindings::pci_unregister_driver(self.driver.get()) }; } } // SAFETY: `Registration` has no fields or methods accessible via `&Registration`, so it is safe to // share references to it with multiple threads as nothing can be done. unsafe impl<T> Sync for Registration<T> where T: Driver {} // SAFETY: Both registration and unregistration are implemented in C and safe to be performed from // any thread, so `Registration` is `Send`. unsafe impl<T> Send for Registration<T> where T: Driver {}
samples/rust/rust_pci_driver/mod.rs
// SPDX-License-Identifier: GPL-2.0 //! Rust PCI driver sample. mod driver; use kernel::{pci, prelude::*}; module! { type: Module, name: "rust_pci_driver_sample", author: "Danilo Krummrich", description: "Rust PCI driver sample", license: "GPL", } struct Module { _reg: pci::Registration<driver::Driver>, } impl kernel::Module for Module { fn init(name: &'static CStr, module: &'static ThisModule) -> Result<Self> { Ok(Module { _reg: pci::Registration::new(name, module)?, }) } }
samples/rust/rust_pci_driver/driver.rs
// SPDX-License-Identifier: GPL-2.0 //! Rust PCI driver sample use kernel::{bindings, pci, prelude::*}; const PCI_DEVICE_ID_REDHAT_QEMU_PCI_TESTDEV: u32 = 0x0005; pub(crate) struct Driver; impl Driver { const IDS: usize = 2; const __ID_TABLE: [bindings::pci_device_id; Self::IDS] = Self::id_table(); const fn id_table() -> [bindings::pci_device_id; Self::IDS] { // SAFETY: `bindings::pci_device_id` is valid to be zero initialized. let mut id: bindings::pci_device_id = unsafe { core::mem::zeroed() }; id.vendor = bindings::PCI_VENDOR_ID_REDHAT; id.device = PCI_DEVICE_ID_REDHAT_QEMU_PCI_TESTDEV; id.subvendor = bindings::PCI_ANY_ID as u32; id.subdevice = bindings::PCI_ANY_ID as u32; // SAFETY: `bindings::pci_device_id` is valid to be zero initialized. let sentinel: bindings::pci_device_id = unsafe { core::mem::zeroed() }; [id, sentinel] } } impl pci::Driver for Driver { const ID_TABLE: *const bindings::pci_device_id = Self::__ID_TABLE.as_ptr(); fn probe(_pdev: *mut bindings::pci_dev) -> Result { pr_info!("Probe Rust PCI driver sample.\n"); Ok(()) } fn remove(_pdev: *mut bindings::pci_dev) { pr_info!("Remove Rust PCI driver sample.\n"); } }
Registration
type ensures that a driver is unregistered eventuallyrust/kernel/driver.rs
// SPDX-License-Identifier: GPL-2.0 //! Generic driver support use core::cell::UnsafeCell; use core::marker::PhantomData; use kernel::{alloc::flags::*, prelude::*}; /// The [`RegistrationOps`] trait serves as generic interface for subsystems (e.g., PCI, Platform, /// Amba, etc.) to privide the corresponding subsystem specific implementation to register / /// unregister a driver of the particular type (`RegType`). /// /// For instance, the PCI subsystem would set `RegType` to `bindings::pci_driver` and call /// `bindings::__pci_register_driver` from `RegistrationOps::register` and /// `bindings::pci_unregister_driver` from `RegistrationOps::unregister`. pub trait RegistrationOps { /// The type that holds information about the registration. This is typically a struct defined /// by the C portion of the kernel, e.g. `bindings::pci_driver. type RegType: Default; /// Registers a driver. /// /// # Safety /// /// `reg` must point to valid, initialised, and writable memory. It may be modified by this /// function to hold registration state. /// /// On success, `reg` must remain pinned and valid until the matching call to /// [`RegistrationOps::unregister`]. unsafe fn register( reg: *mut Self::RegType, name: &'static CStr, module: &'static ThisModule, ) -> Result; /// Unregisters a driver previously registered with [`RegistrationOps::register`]. /// /// # Safety /// /// `reg` must point to valid writable memory, initialised by a previous successful call to /// [`RegistrationOps::register`]. unsafe fn unregister(reg: *mut Self::RegType); } /// Registration structure for a driver. /// /// The existance of an instance of this structure implies that the corresponding driver is /// currently registered. pub struct Registration<T: RegistrationOps> { driver: Pin<KBox<UnsafeCell<T::RegType>>>, _p: PhantomData<T>, } impl<T> Registration<T> where T: RegistrationOps, { /// Register a new driver from `T::RegType`. pub fn new(name: &'static CStr, module: &'static ThisModule) -> Result<Self> { let driver = KBox::pin(UnsafeCell::new(T::RegType::default()), GFP_KERNEL)?; // SAFETY: `driver` has just been initialized; it's only freed after `Self::drop`, which // calls `T::unregister` first. unsafe { T::register(driver.get(), name, module) }?; Ok(Self { driver, _p: PhantomData::<T>, }) } } impl<T> Drop for Registration<T> where T: RegistrationOps, { fn drop(&mut self) { // SAFETY: Only ever called if the `Registration` was created successfully. unsafe { T::unregister(self.driver.get()) }; } } // SAFETY: `Registration` has no fields or methods accessible via `&Registration`, so it is safe to // share references to it with multiple threads as nothing can be done. unsafe impl<T> Sync for Registration<T> where T: RegistrationOps {} // SAFETY: Both registration and unregistration are implemented in C and safe to be performed from // any thread, so `Registration` is `Send`. unsafe impl<T> Send for Registration<T> where T: RegistrationOps {}
// SPDX-License-Identifier: GPL-2.0 //! Generic driver support use core::cell::UnsafeCell; use core::marker::PhantomData; use kernel::{alloc::flags::*, prelude::*}; /// The [`RegistrationOps`] trait serves as generic interface for subsystems (e.g., PCI, Platform, /// Amba, etc.) to privide the corresponding subsystem specific implementation to register / /// unregister a driver of the particular type (`RegType`). /// /// For instance, the PCI subsystem would set `RegType` to `bindings::pci_driver` and call /// `bindings::__pci_register_driver` from `RegistrationOps::register` and /// `bindings::pci_unregister_driver` from `RegistrationOps::unregister`. pub trait RegistrationOps { /// The type that holds information about the registration. This is typically a struct defined /// by the C portion of the kernel, e.g. `bindings::pci_driver. type RegType: Default; /// Registers a driver. /// /// # Safety /// /// `reg` must point to valid, initialised, and writable memory. It may be modified by this /// function to hold registration state. /// /// On success, `reg` must remain pinned and valid until the matching call to /// [`RegistrationOps::unregister`]. unsafe fn register( reg: *mut Self::RegType, name: &'static CStr, module: &'static ThisModule, ) -> Result; /// Unregisters a driver previously registered with [`RegistrationOps::register`]. /// /// # Safety /// /// `reg` must point to valid writable memory, initialised by a previous successful call to /// [`RegistrationOps::register`]. unsafe fn unregister(reg: *mut Self::RegType); } /// Registration structure for a driver. /// /// The existance of an instance of this structure implies that the corresponding driver is /// currently registered. pub struct Registration<T: RegistrationOps> { driver: Pin<KBox<UnsafeCell<T::RegType>>>, _p: PhantomData<T>, } impl<T> Registration<T> where T: RegistrationOps, { /// Register a new driver from `T::RegType`. pub fn new(name: &'static CStr, module: &'static ThisModule) -> Result<Self> { let driver = KBox::pin(UnsafeCell::new(T::RegType::default()), GFP_KERNEL)?; // SAFETY: `driver` has just been initialized; it's only freed after `Self::drop`, which // calls `T::unregister` first. unsafe { T::register(driver.get(), name, module) }?; Ok(Self { driver, _p: PhantomData::<T>, }) } } impl<T> Drop for Registration<T> where T: RegistrationOps, { fn drop(&mut self) { // SAFETY: Only ever called if the `Registration` was created successfully. unsafe { T::unregister(self.driver.get()) }; } } // SAFETY: `Registration` has no fields or methods accessible via `&Registration`, so it is safe to // share references to it with multiple threads as nothing can be done. unsafe impl<T> Sync for Registration<T> where T: RegistrationOps {} // SAFETY: Both registration and unregistration are implemented in C and safe to be performed from // any thread, so `Registration` is `Send`. unsafe impl<T> Send for Registration<T> where T: RegistrationOps {}
// SPDX-License-Identifier: GPL-2.0 //! Generic driver support use core::cell::UnsafeCell; use core::marker::PhantomData; use kernel::{alloc::flags::*, prelude::*}; /// The [`RegistrationOps`] trait serves as generic interface for subsystems (e.g., PCI, Platform, /// Amba, etc.) to privide the corresponding subsystem specific implementation to register / /// unregister a driver of the particular type (`RegType`). /// /// For instance, the PCI subsystem would set `RegType` to `bindings::pci_driver` and call /// `bindings::__pci_register_driver` from `RegistrationOps::register` and /// `bindings::pci_unregister_driver` from `RegistrationOps::unregister`. pub trait RegistrationOps { /// The type that holds information about the registration. This is typically a struct defined /// by the C portion of the kernel, e.g. `bindings::pci_driver. type RegType: Default; /// Registers a driver. /// /// # Safety /// /// `reg` must point to valid, initialised, and writable memory. It may be modified by this /// function to hold registration state. /// /// On success, `reg` must remain pinned and valid until the matching call to /// [`RegistrationOps::unregister`]. unsafe fn register( reg: *mut Self::RegType, name: &'static CStr, module: &'static ThisModule, ) -> Result; /// Unregisters a driver previously registered with [`RegistrationOps::register`]. /// /// # Safety /// /// `reg` must point to valid writable memory, initialised by a previous successful call to /// [`RegistrationOps::register`]. unsafe fn unregister(reg: *mut Self::RegType); } /// Registration structure for a driver. /// /// The existance of an instance of this structure implies that the corresponding driver is /// currently registered. pub struct Registration<T: RegistrationOps> { driver: Pin<KBox<UnsafeCell<T::RegType>>>, _p: PhantomData<T>, } impl<T> Registration<T> where T: RegistrationOps, { /// Register a new driver from `T::RegType`. pub fn new(name: &'static CStr, module: &'static ThisModule) -> Result<Self> { let driver = KBox::pin(UnsafeCell::new(T::RegType::default()), GFP_KERNEL)?; // SAFETY: `driver` has just been initialized; it's only freed after `Self::drop`, which // calls `T::unregister` first. unsafe { T::register(driver.get(), name, module) }?; Ok(Self { driver, _p: PhantomData::<T>, }) } } impl<T> Drop for Registration<T> where T: RegistrationOps, { fn drop(&mut self) { // SAFETY: Only ever called if the `Registration` was created successfully. unsafe { T::unregister(self.driver.get()) }; } } // SAFETY: `Registration` has no fields or methods accessible via `&Registration`, so it is safe to // share references to it with multiple threads as nothing can be done. unsafe impl<T> Sync for Registration<T> where T: RegistrationOps {} // SAFETY: Both registration and unregistration are implemented in C and safe to be performed from // any thread, so `Registration` is `Send`. unsafe impl<T> Send for Registration<T> where T: RegistrationOps {}
// SPDX-License-Identifier: GPL-2.0 //! Generic driver support use core::cell::UnsafeCell; use core::marker::PhantomData; use kernel::{alloc::flags::*, prelude::*}; /// The [`RegistrationOps`] trait serves as generic interface for subsystems (e.g., PCI, Platform, /// Amba, etc.) to privide the corresponding subsystem specific implementation to register / /// unregister a driver of the particular type (`RegType`). /// /// For instance, the PCI subsystem would set `RegType` to `bindings::pci_driver` and call /// `bindings::__pci_register_driver` from `RegistrationOps::register` and /// `bindings::pci_unregister_driver` from `RegistrationOps::unregister`. pub trait RegistrationOps { /// The type that holds information about the registration. This is typically a struct defined /// by the C portion of the kernel, e.g. `bindings::pci_driver. type RegType: Default; /// Registers a driver. /// /// # Safety /// /// `reg` must point to valid, initialised, and writable memory. It may be modified by this /// function to hold registration state. /// /// On success, `reg` must remain pinned and valid until the matching call to /// [`RegistrationOps::unregister`]. unsafe fn register( reg: *mut Self::RegType, name: &'static CStr, module: &'static ThisModule, ) -> Result; /// Unregisters a driver previously registered with [`RegistrationOps::register`]. /// /// # Safety /// /// `reg` must point to valid writable memory, initialised by a previous successful call to /// [`RegistrationOps::register`]. unsafe fn unregister(reg: *mut Self::RegType); } /// Registration structure for a driver. /// /// The existance of an instance of this structure implies that the corresponding driver is /// currently registered. pub struct Registration<T: RegistrationOps> { driver: Pin<KBox<UnsafeCell<T::RegType>>>, _p: PhantomData<T>, } impl<T> Registration<T> where T: RegistrationOps, { /// Register a new driver from `T::RegType`. pub fn new(name: &'static CStr, module: &'static ThisModule) -> Result<Self> { let driver = KBox::pin(UnsafeCell::new(T::RegType::default()), GFP_KERNEL)?; // SAFETY: `driver` has just been initialized; it's only freed after `Self::drop`, which // calls `T::unregister` first. unsafe { T::register(driver.get(), name, module) }?; Ok(Self { driver, _p: PhantomData::<T>, }) } } impl<T> Drop for Registration<T> where T: RegistrationOps, { fn drop(&mut self) { // SAFETY: Only ever called if the `Registration` was created successfully. unsafe { T::unregister(self.driver.get()) }; } } // SAFETY: `Registration` has no fields or methods accessible via `&Registration`, so it is safe to // share references to it with multiple threads as nothing can be done. unsafe impl<T> Sync for Registration<T> where T: RegistrationOps {} // SAFETY: Both registration and unregistration are implemented in C and safe to be performed from // any thread, so `Registration` is `Send`. unsafe impl<T> Send for Registration<T> where T: RegistrationOps {}
rust/kernel/pci.rs
// SPDX-License-Identifier: GPL-2.0 //! Wrappers for the PCI subsystem //! //! C header: [`include/linux/pci.h`](srctree/include/linux/pci.h) use core::marker::PhantomData; use kernel::{ bindings, driver, error::{from_result, to_result}, prelude::*, }; /// Drivers must implement this trait to register a PCI driver. pub trait Driver { /// Pointer to the PCI driver's ID table. /// /// This is highly unsafe, since we have to trust the driver, that the provided pointer is /// valid. const ID_TABLE: *const bindings::pci_device_id; /// PCI driver probe. /// /// Called when a PCI device is matched against a PCI driver. fn probe(pdev: *mut bindings::pci_dev) -> Result; /// PCI driver remove. /// /// Called when the PCI device is unbound. fn remove(pdev: *mut bindings::pci_dev); } /// PCI abstraction for registering PCI drivers. pub struct Adapter<T: Driver>(PhantomData<T>); impl<T> Adapter<T> where T: Driver, { extern "C" fn probe( pdev: *mut bindings::pci_dev, _ent: *const bindings::pci_device_id, ) -> core::ffi::c_int { from_result(|| { T::probe(pdev)?; Ok(0) }) } extern "C" fn remove(pdev: *mut bindings::pci_dev) { T::remove(pdev); } } impl<T> driver::RegistrationOps for Adapter<T> where T: Driver, { type RegType = bindings::pci_driver; unsafe fn register( pdrv: *mut Self::RegType, name: &'static CStr, module: &'static ThisModule, ) -> Result { // SAFETY: By the safety requirements of this function `pdrv` is valid; we never move out // of `pdrv`. let pdrv = unsafe { &mut *pdrv }; pdrv.name = name.as_char_ptr(); pdrv.probe = Some(Self::probe); pdrv.remove = Some(Self::remove); pdrv.id_table = T::ID_TABLE; // SAFETY: `pdrv` is a valid `struct pci_driver`; `ThisModule` is equivalent to // C's `THIS_MODULE` and hence valid for `__pci_register_driver`. `name` is passed as `NULL` // terminated C string. // // Returns zero when the driver was registered successfully, a non-zero error code // otherwise, which is handled by `to_result`. to_result(unsafe { bindings::__pci_register_driver(pdrv, module.as_ptr(), name.as_char_ptr()) }) } unsafe fn unregister(pdrv: *mut Self::RegType) { // SAFETY: `pdrv` is guaranteed to be a valid `RegType`. unsafe { bindings::pci_unregister_driver(pdrv) } } }
samples/rust/rust_pci_driver/mod.rs
// SPDX-License-Identifier: GPL-2.0 //! Rust PCI driver sample. mod driver; use kernel::{pci, prelude::*}; module! { type: Module, name: "rust_pci_driver_sample", author: "Danilo Krummrich", description: "Rust PCI driver sample", license: "GPL", } struct Module { _reg: kernel::driver::Registration<pci::Adapter<driver::Driver>>, } impl kernel::Module for Module { fn init(name: &'static CStr, module: &'static ThisModule) -> Result<Self> { Ok(Module { _reg: kernel::driver::Registration::new(name, module)?, }) } }
Registration
typeBox
to allocate driver structures, but use static allocation through InPlaceModule
insteadrust/kernel/pci.rs
// SPDX-License-Identifier: GPL-2.0 //! Wrappers for the PCI subsystem //! //! C header: [`include/linux/pci.h`](srctree/include/linux/pci.h) use core::marker::PhantomData; use kernel::{ bindings, driver, error::{from_result, to_result}, prelude::*, }; /// Abstraction for `bindings::pci_device_id`. #[derive(Clone, Copy)] pub struct DeviceId { /// Vendor ID pub vendor: u32, /// Device ID pub device: u32, /// Subsystem vendor ID pub subvendor: u32, /// Subsystem device ID pub subdevice: u32, /// Device class and subclass pub class: u32, /// Limit which sub-fields of the class pub class_mask: u32, } impl DeviceId { /// Zeroed `bindings::pci_device_id`. // SAFETY; The all-zero byte-pattern is valid for `bindings::pci_device_id`. pub const ZERO: bindings::pci_device_id = unsafe { core::mem::zeroed() }; const PCI_ANY_ID: u32 = !0; /// Equivalent to the PCI_DEVICE macro. pub const fn new(vendor: u32, device: u32) -> Self { Self { vendor, device, subvendor: DeviceId::PCI_ANY_ID, subdevice: DeviceId::PCI_ANY_ID, class: 0, class_mask: 0, } } /// Convert `DeviceId` to raw `bindings::pci_device_id`. pub const fn to_rawid(&self) -> bindings::pci_device_id { let mut raw = Self::ZERO; raw.vendor = self.vendor; raw.device = self.device; raw.subvendor = self.subvendor; raw.subdevice = self.subdevice; raw.class = self.class; raw.class_mask = self.class_mask; raw } } /// A zero-terminated PCI device ID array. #[repr(C)] pub struct IdArray<const N: usize> { ids: [bindings::pci_device_id; N], sentinel: bindings::pci_device_id, } impl<const N: usize> IdArray<N> { /// Creates a new instance of the ID array. /// /// The contents are derived from the given identifiers. #[doc(hidden)] pub const fn new(ids: [bindings::pci_device_id; N]) -> Self { Self { ids, sentinel: DeviceId::ZERO, } } /// Returns an `IdTable` backed by `self`. /// /// This is used to essentially erase the array size. pub const fn as_table(&self) -> IdTable<'_> { IdTable { first: &self.ids[0], } } } /// A device ID table. /// /// The table is guaranteed to be zero-terminated. #[repr(C)] pub struct IdTable<'a> { first: &'a bindings::pci_device_id, } impl AsRef<bindings::pci_device_id> for IdTable<'_> { fn as_ref(&self) -> &bindings::pci_device_id { self.first } } /// Counts the number of parenthesis-delimited, comma-separated items. #[macro_export] macro_rules! count_paren_items { (($($item:tt)*), $($remaining:tt)*) => { 1 + $crate::count_paren_items!($($remaining)*) }; (($($item:tt)*)) => { 1 }; () => { 0 }; } #[macro_export] #[doc(hidden)] macro_rules! define_pci_id_array { ($($args:tt)*) => {{ const fn new<const N: usize>(ids: [$crate::pci::DeviceId; N]) -> $crate::pci::IdArray<N> { let mut raw_ids = [$crate::pci::DeviceId::ZERO; N]; let mut i = 0usize; while i < N { raw_ids[i] = ids[i].to_rawid(); i += 1; } $crate::pci::IdArray::<N>::new(raw_ids) } new([ $($args)* ]) }} } /// Define a const PCI device ID table. #[macro_export] macro_rules! define_pci_id_table { ([ $($args:tt)* ]) => { const ID_TABLE: $crate::pci::IdTable<'static> = { const ARRAY: $crate::pci::IdArray<{ $crate::count_paren_items!($($args)*) }> = $crate::define_pci_id_array!($($args)*); ARRAY.as_table() }; }; } pub use define_pci_id_table; /// Drivers must implement this trait to register a PCI driver. pub trait Driver { /// The table of device IDs supported by this driver. const ID_TABLE: IdTable<'static>; /// PCI driver probe. /// /// Called when a PCI device is matched against a PCI driver. fn probe(pdev: *mut bindings::pci_dev) -> Result; /// PCI driver remove. /// /// Called when the PCI device is unbound. fn remove(pdev: *mut bindings::pci_dev); } /// PCI abstraction for registering PCI drivers. pub struct Adapter<T: Driver>(PhantomData<T>); impl<T> Adapter<T> where T: Driver, { extern "C" fn probe( pdev: *mut bindings::pci_dev, _ent: *const bindings::pci_device_id, ) -> core::ffi::c_int { from_result(|| { T::probe(pdev)?; Ok(0) }) } extern "C" fn remove(pdev: *mut bindings::pci_dev) { T::remove(pdev); } } impl<T> driver::RegistrationOps for Adapter<T> where T: Driver, { type RegType = bindings::pci_driver; unsafe fn register( pdrv: *mut Self::RegType, name: &'static CStr, module: &'static ThisModule, ) -> Result { // SAFETY: By the safety requirements of this function `pdrv` is valid; we never move out // of `pdrv`. let pdrv = unsafe { &mut *pdrv }; pdrv.name = name.as_char_ptr(); pdrv.probe = Some(Self::probe); pdrv.remove = Some(Self::remove); pdrv.id_table = T::ID_TABLE.as_ref(); // SAFETY: `pdrv` is a valid `struct pci_driver`; `ThisModule` is equivalent to // C's `THIS_MODULE` and hence valid for `__pci_register_driver`. `name` is passed as `NULL` // terminated C string. // // Returns zero when the driver was registered successfully, a non-zero error code // otherwise, which is handled by `to_result`. to_result(unsafe { bindings::__pci_register_driver(pdrv, module.as_ptr(), name.as_char_ptr()) }) } unsafe fn unregister(pdrv: *mut Self::RegType) { // SAFETY: `pdrv` is guaranteed to be a valid `RegType`. unsafe { bindings::pci_unregister_driver(pdrv) } } }
// SPDX-License-Identifier: GPL-2.0 //! Wrappers for the PCI subsystem //! //! C header: [`include/linux/pci.h`](srctree/include/linux/pci.h) use core::marker::PhantomData; use kernel::{ bindings, driver, error::{from_result, to_result}, prelude::*, }; /// Abstraction for `bindings::pci_device_id`. #[derive(Clone, Copy)] pub struct DeviceId { /// Vendor ID pub vendor: u32, /// Device ID pub device: u32, /// Subsystem vendor ID pub subvendor: u32, /// Subsystem device ID pub subdevice: u32, /// Device class and subclass pub class: u32, /// Limit which sub-fields of the class pub class_mask: u32, } impl DeviceId { /// Zeroed `bindings::pci_device_id`. // SAFETY; The all-zero byte-pattern is valid for `bindings::pci_device_id`. pub const ZERO: bindings::pci_device_id = unsafe { core::mem::zeroed() }; const PCI_ANY_ID: u32 = !0; /// Equivalent to the PCI_DEVICE macro. pub const fn new(vendor: u32, device: u32) -> Self { Self { vendor, device, subvendor: DeviceId::PCI_ANY_ID, subdevice: DeviceId::PCI_ANY_ID, class: 0, class_mask: 0, } } /// Convert `DeviceId` to raw `bindings::pci_device_id`. pub const fn to_rawid(&self) -> bindings::pci_device_id { let mut raw = Self::ZERO; raw.vendor = self.vendor; raw.device = self.device; raw.subvendor = self.subvendor; raw.subdevice = self.subdevice; raw.class = self.class; raw.class_mask = self.class_mask; raw } } /// A zero-terminated PCI device ID array. #[repr(C)] pub struct IdArray<const N: usize> { ids: [bindings::pci_device_id; N], sentinel: bindings::pci_device_id, } impl<const N: usize> IdArray<N> { /// Creates a new instance of the ID array. /// /// The contents are derived from the given identifiers. #[doc(hidden)] pub const fn new(ids: [bindings::pci_device_id; N]) -> Self { Self { ids, sentinel: DeviceId::ZERO, } } /// Returns an `IdTable` backed by `self`. /// /// This is used to essentially erase the array size. pub const fn as_table(&self) -> IdTable<'_> { IdTable { first: &self.ids[0], } } } /// A device ID table. /// /// The table is guaranteed to be zero-terminated. #[repr(C)] pub struct IdTable<'a> { first: &'a bindings::pci_device_id, } impl AsRef<bindings::pci_device_id> for IdTable<'_> { fn as_ref(&self) -> &bindings::pci_device_id { self.first } } /// Counts the number of parenthesis-delimited, comma-separated items. #[macro_export] macro_rules! count_paren_items { (($($item:tt)*), $($remaining:tt)*) => { 1 + $crate::count_paren_items!($($remaining)*) }; (($($item:tt)*)) => { 1 }; () => { 0 }; } #[macro_export] #[doc(hidden)] macro_rules! define_pci_id_array { ($($args:tt)*) => {{ const fn new<const N: usize>(ids: [$crate::pci::DeviceId; N]) -> $crate::pci::IdArray<N> { let mut raw_ids = [$crate::pci::DeviceId::ZERO; N]; let mut i = 0usize; while i < N { raw_ids[i] = ids[i].to_rawid(); i += 1; } $crate::pci::IdArray::<N>::new(raw_ids) } new([ $($args)* ]) }} } /// Define a const PCI device ID table. #[macro_export] macro_rules! define_pci_id_table { ([ $($args:tt)* ]) => { const ID_TABLE: $crate::pci::IdTable<'static> = { const ARRAY: $crate::pci::IdArray<{ $crate::count_paren_items!($($args)*) }> = $crate::define_pci_id_array!($($args)*); ARRAY.as_table() }; }; } pub use define_pci_id_table; /// Drivers must implement this trait to register a PCI driver. pub trait Driver { /// The table of device IDs supported by this driver. const ID_TABLE: IdTable<'static>; /// PCI driver probe. /// /// Called when a PCI device is matched against a PCI driver. fn probe(pdev: *mut bindings::pci_dev) -> Result; /// PCI driver remove. /// /// Called when the PCI device is unbound. fn remove(pdev: *mut bindings::pci_dev); } /// PCI abstraction for registering PCI drivers. pub struct Adapter<T: Driver>(PhantomData<T>); impl<T> Adapter<T> where T: Driver, { extern "C" fn probe( pdev: *mut bindings::pci_dev, _ent: *const bindings::pci_device_id, ) -> core::ffi::c_int { from_result(|| { T::probe(pdev)?; Ok(0) }) } extern "C" fn remove(pdev: *mut bindings::pci_dev) { T::remove(pdev); } } impl<T> driver::RegistrationOps for Adapter<T> where T: Driver, { type RegType = bindings::pci_driver; unsafe fn register( pdrv: *mut Self::RegType, name: &'static CStr, module: &'static ThisModule, ) -> Result { // SAFETY: By the safety requirements of this function `pdrv` is valid; we never move out // of `pdrv`. let pdrv = unsafe { &mut *pdrv }; pdrv.name = name.as_char_ptr(); pdrv.probe = Some(Self::probe); pdrv.remove = Some(Self::remove); pdrv.id_table = T::ID_TABLE.as_ref(); // SAFETY: `pdrv` is a valid `struct pci_driver`; `ThisModule` is equivalent to // C's `THIS_MODULE` and hence valid for `__pci_register_driver`. `name` is passed as `NULL` // terminated C string. // // Returns zero when the driver was registered successfully, a non-zero error code // otherwise, which is handled by `to_result`. to_result(unsafe { bindings::__pci_register_driver(pdrv, module.as_ptr(), name.as_char_ptr()) }) } unsafe fn unregister(pdrv: *mut Self::RegType) { // SAFETY: `pdrv` is guaranteed to be a valid `RegType`. unsafe { bindings::pci_unregister_driver(pdrv) } } }
// SPDX-License-Identifier: GPL-2.0 //! Wrappers for the PCI subsystem //! //! C header: [`include/linux/pci.h`](srctree/include/linux/pci.h) use core::marker::PhantomData; use kernel::{ bindings, driver, error::{from_result, to_result}, prelude::*, }; /// Abstraction for `bindings::pci_device_id`. #[derive(Clone, Copy)] pub struct DeviceId { /// Vendor ID pub vendor: u32, /// Device ID pub device: u32, /// Subsystem vendor ID pub subvendor: u32, /// Subsystem device ID pub subdevice: u32, /// Device class and subclass pub class: u32, /// Limit which sub-fields of the class pub class_mask: u32, } impl DeviceId { /// Zeroed `bindings::pci_device_id`. // SAFETY; The all-zero byte-pattern is valid for `bindings::pci_device_id`. pub const ZERO: bindings::pci_device_id = unsafe { core::mem::zeroed() }; const PCI_ANY_ID: u32 = !0; /// Equivalent to the PCI_DEVICE macro. pub const fn new(vendor: u32, device: u32) -> Self { Self { vendor, device, subvendor: DeviceId::PCI_ANY_ID, subdevice: DeviceId::PCI_ANY_ID, class: 0, class_mask: 0, } } /// Convert `DeviceId` to raw `bindings::pci_device_id`. pub const fn to_rawid(&self) -> bindings::pci_device_id { let mut raw = Self::ZERO; raw.vendor = self.vendor; raw.device = self.device; raw.subvendor = self.subvendor; raw.subdevice = self.subdevice; raw.class = self.class; raw.class_mask = self.class_mask; raw } } /// A zero-terminated PCI device ID array. #[repr(C)] pub struct IdArray<const N: usize> { ids: [bindings::pci_device_id; N], sentinel: bindings::pci_device_id, } impl<const N: usize> IdArray<N> { /// Creates a new instance of the ID array. /// /// The contents are derived from the given identifiers. #[doc(hidden)] pub const fn new(ids: [bindings::pci_device_id; N]) -> Self { Self { ids, sentinel: DeviceId::ZERO, } } /// Returns an `IdTable` backed by `self`. /// /// This is used to essentially erase the array size. pub const fn as_table(&self) -> IdTable<'_> { IdTable { first: &self.ids[0], } } } /// A device ID table. /// /// The table is guaranteed to be zero-terminated. #[repr(C)] pub struct IdTable<'a> { first: &'a bindings::pci_device_id, } impl AsRef<bindings::pci_device_id> for IdTable<'_> { fn as_ref(&self) -> &bindings::pci_device_id { self.first } } /// Counts the number of parenthesis-delimited, comma-separated items. #[macro_export] macro_rules! count_paren_items { (($($item:tt)*), $($remaining:tt)*) => { 1 + $crate::count_paren_items!($($remaining)*) }; (($($item:tt)*)) => { 1 }; () => { 0 }; } #[macro_export] #[doc(hidden)] macro_rules! define_pci_id_array { ($($args:tt)*) => {{ const fn new<const N: usize>(ids: [$crate::pci::DeviceId; N]) -> $crate::pci::IdArray<N> { let mut raw_ids = [$crate::pci::DeviceId::ZERO; N]; let mut i = 0usize; while i < N { raw_ids[i] = ids[i].to_rawid(); i += 1; } $crate::pci::IdArray::<N>::new(raw_ids) } new([ $($args)* ]) }} } /// Define a const PCI device ID table. #[macro_export] macro_rules! define_pci_id_table { ([ $($args:tt)* ]) => { const ID_TABLE: $crate::pci::IdTable<'static> = { const ARRAY: $crate::pci::IdArray<{ $crate::count_paren_items!($($args)*) }> = $crate::define_pci_id_array!($($args)*); ARRAY.as_table() }; }; } pub use define_pci_id_table; /// Drivers must implement this trait to register a PCI driver. pub trait Driver { /// The table of device IDs supported by this driver. const ID_TABLE: IdTable<'static>; /// PCI driver probe. /// /// Called when a PCI device is matched against a PCI driver. fn probe(pdev: *mut bindings::pci_dev) -> Result; /// PCI driver remove. /// /// Called when the PCI device is unbound. fn remove(pdev: *mut bindings::pci_dev); } /// PCI abstraction for registering PCI drivers. pub struct Adapter<T: Driver>(PhantomData<T>); impl<T> Adapter<T> where T: Driver, { extern "C" fn probe( pdev: *mut bindings::pci_dev, _ent: *const bindings::pci_device_id, ) -> core::ffi::c_int { from_result(|| { T::probe(pdev)?; Ok(0) }) } extern "C" fn remove(pdev: *mut bindings::pci_dev) { T::remove(pdev); } } impl<T> driver::RegistrationOps for Adapter<T> where T: Driver, { type RegType = bindings::pci_driver; unsafe fn register( pdrv: *mut Self::RegType, name: &'static CStr, module: &'static ThisModule, ) -> Result { // SAFETY: By the safety requirements of this function `pdrv` is valid; we never move out // of `pdrv`. let pdrv = unsafe { &mut *pdrv }; pdrv.name = name.as_char_ptr(); pdrv.probe = Some(Self::probe); pdrv.remove = Some(Self::remove); pdrv.id_table = T::ID_TABLE.as_ref(); // SAFETY: `pdrv` is a valid `struct pci_driver`; `ThisModule` is equivalent to // C's `THIS_MODULE` and hence valid for `__pci_register_driver`. `name` is passed as `NULL` // terminated C string. // // Returns zero when the driver was registered successfully, a non-zero error code // otherwise, which is handled by `to_result`. to_result(unsafe { bindings::__pci_register_driver(pdrv, module.as_ptr(), name.as_char_ptr()) }) } unsafe fn unregister(pdrv: *mut Self::RegType) { // SAFETY: `pdrv` is guaranteed to be a valid `RegType`. unsafe { bindings::pci_unregister_driver(pdrv) } } }
// SPDX-License-Identifier: GPL-2.0 //! Wrappers for the PCI subsystem //! //! C header: [`include/linux/pci.h`](srctree/include/linux/pci.h) use core::marker::PhantomData; use kernel::{ bindings, driver, error::{from_result, to_result}, prelude::*, }; /// Abstraction for `bindings::pci_device_id`. #[derive(Clone, Copy)] pub struct DeviceId { /// Vendor ID pub vendor: u32, /// Device ID pub device: u32, /// Subsystem vendor ID pub subvendor: u32, /// Subsystem device ID pub subdevice: u32, /// Device class and subclass pub class: u32, /// Limit which sub-fields of the class pub class_mask: u32, } impl DeviceId { /// Zeroed `bindings::pci_device_id`. // SAFETY; The all-zero byte-pattern is valid for `bindings::pci_device_id`. pub const ZERO: bindings::pci_device_id = unsafe { core::mem::zeroed() }; const PCI_ANY_ID: u32 = !0; /// Equivalent to the PCI_DEVICE macro. pub const fn new(vendor: u32, device: u32) -> Self { Self { vendor, device, subvendor: DeviceId::PCI_ANY_ID, subdevice: DeviceId::PCI_ANY_ID, class: 0, class_mask: 0, } } /// Convert `DeviceId` to raw `bindings::pci_device_id`. pub const fn to_rawid(&self) -> bindings::pci_device_id { let mut raw = Self::ZERO; raw.vendor = self.vendor; raw.device = self.device; raw.subvendor = self.subvendor; raw.subdevice = self.subdevice; raw.class = self.class; raw.class_mask = self.class_mask; raw } } /// A zero-terminated PCI device ID array. #[repr(C)] pub struct IdArray<const N: usize> { ids: [bindings::pci_device_id; N], sentinel: bindings::pci_device_id, } impl<const N: usize> IdArray<N> { /// Creates a new instance of the ID array. /// /// The contents are derived from the given identifiers. #[doc(hidden)] pub const fn new(ids: [bindings::pci_device_id; N]) -> Self { Self { ids, sentinel: DeviceId::ZERO, } } /// Returns an `IdTable` backed by `self`. /// /// This is used to essentially erase the array size. pub const fn as_table(&self) -> IdTable<'_> { IdTable { first: &self.ids[0], } } } /// A device ID table. /// /// The table is guaranteed to be zero-terminated. #[repr(C)] pub struct IdTable<'a> { first: &'a bindings::pci_device_id, } impl AsRef<bindings::pci_device_id> for IdTable<'_> { fn as_ref(&self) -> &bindings::pci_device_id { self.first } } /// Counts the number of parenthesis-delimited, comma-separated items. #[macro_export] macro_rules! count_paren_items { (($($item:tt)*), $($remaining:tt)*) => { 1 + $crate::count_paren_items!($($remaining)*) }; (($($item:tt)*)) => { 1 }; () => { 0 }; } #[macro_export] #[doc(hidden)] macro_rules! define_pci_id_array { ($($args:tt)*) => {{ const fn new<const N: usize>(ids: [$crate::pci::DeviceId; N]) -> $crate::pci::IdArray<N> { let mut raw_ids = [$crate::pci::DeviceId::ZERO; N]; let mut i = 0usize; while i < N { raw_ids[i] = ids[i].to_rawid(); i += 1; } $crate::pci::IdArray::<N>::new(raw_ids) } new([ $($args)* ]) }} } /// Define a const PCI device ID table. #[macro_export] macro_rules! define_pci_id_table { ([ $($args:tt)* ]) => { const ID_TABLE: $crate::pci::IdTable<'static> = { const ARRAY: $crate::pci::IdArray<{ $crate::count_paren_items!($($args)*) }> = $crate::define_pci_id_array!($($args)*); ARRAY.as_table() }; }; } pub use define_pci_id_table; /// Drivers must implement this trait to register a PCI driver. pub trait Driver { /// The table of device IDs supported by this driver. const ID_TABLE: IdTable<'static>; /// PCI driver probe. /// /// Called when a PCI device is matched against a PCI driver. fn probe(pdev: *mut bindings::pci_dev) -> Result; /// PCI driver remove. /// /// Called when the PCI device is unbound. fn remove(pdev: *mut bindings::pci_dev); } /// PCI abstraction for registering PCI drivers. pub struct Adapter<T: Driver>(PhantomData<T>); impl<T> Adapter<T> where T: Driver, { extern "C" fn probe( pdev: *mut bindings::pci_dev, _ent: *const bindings::pci_device_id, ) -> core::ffi::c_int { from_result(|| { T::probe(pdev)?; Ok(0) }) } extern "C" fn remove(pdev: *mut bindings::pci_dev) { T::remove(pdev); } } impl<T> driver::RegistrationOps for Adapter<T> where T: Driver, { type RegType = bindings::pci_driver; unsafe fn register( pdrv: *mut Self::RegType, name: &'static CStr, module: &'static ThisModule, ) -> Result { // SAFETY: By the safety requirements of this function `pdrv` is valid; we never move out // of `pdrv`. let pdrv = unsafe { &mut *pdrv }; pdrv.name = name.as_char_ptr(); pdrv.probe = Some(Self::probe); pdrv.remove = Some(Self::remove); pdrv.id_table = T::ID_TABLE.as_ref(); // SAFETY: `pdrv` is a valid `struct pci_driver`; `ThisModule` is equivalent to // C's `THIS_MODULE` and hence valid for `__pci_register_driver`. `name` is passed as `NULL` // terminated C string. // // Returns zero when the driver was registered successfully, a non-zero error code // otherwise, which is handled by `to_result`. to_result(unsafe { bindings::__pci_register_driver(pdrv, module.as_ptr(), name.as_char_ptr()) }) } unsafe fn unregister(pdrv: *mut Self::RegType) { // SAFETY: `pdrv` is guaranteed to be a valid `RegType`. unsafe { bindings::pci_unregister_driver(pdrv) } } }
// SPDX-License-Identifier: GPL-2.0 //! Wrappers for the PCI subsystem //! //! C header: [`include/linux/pci.h`](srctree/include/linux/pci.h) use core::marker::PhantomData; use kernel::{ bindings, driver, error::{from_result, to_result}, prelude::*, }; /// Abstraction for `bindings::pci_device_id`. #[derive(Clone, Copy)] pub struct DeviceId { /// Vendor ID pub vendor: u32, /// Device ID pub device: u32, /// Subsystem vendor ID pub subvendor: u32, /// Subsystem device ID pub subdevice: u32, /// Device class and subclass pub class: u32, /// Limit which sub-fields of the class pub class_mask: u32, } impl DeviceId { /// Zeroed `bindings::pci_device_id`. // SAFETY; The all-zero byte-pattern is valid for `bindings::pci_device_id`. pub const ZERO: bindings::pci_device_id = unsafe { core::mem::zeroed() }; const PCI_ANY_ID: u32 = !0; /// Equivalent to the PCI_DEVICE macro. pub const fn new(vendor: u32, device: u32) -> Self { Self { vendor, device, subvendor: DeviceId::PCI_ANY_ID, subdevice: DeviceId::PCI_ANY_ID, class: 0, class_mask: 0, } } /// Convert `DeviceId` to raw `bindings::pci_device_id`. pub const fn to_rawid(&self) -> bindings::pci_device_id { let mut raw = Self::ZERO; raw.vendor = self.vendor; raw.device = self.device; raw.subvendor = self.subvendor; raw.subdevice = self.subdevice; raw.class = self.class; raw.class_mask = self.class_mask; raw } } /// A zero-terminated PCI device ID array. #[repr(C)] pub struct IdArray<const N: usize> { ids: [bindings::pci_device_id; N], sentinel: bindings::pci_device_id, } impl<const N: usize> IdArray<N> { /// Creates a new instance of the ID array. /// /// The contents are derived from the given identifiers. #[doc(hidden)] pub const fn new(ids: [bindings::pci_device_id; N]) -> Self { Self { ids, sentinel: DeviceId::ZERO, } } /// Returns an `IdTable` backed by `self`. /// /// This is used to essentially erase the array size. pub const fn as_table(&self) -> IdTable<'_> { IdTable { first: &self.ids[0], } } } /// A device ID table. /// /// The table is guaranteed to be zero-terminated. #[repr(C)] pub struct IdTable<'a> { first: &'a bindings::pci_device_id, } impl AsRef<bindings::pci_device_id> for IdTable<'_> { fn as_ref(&self) -> &bindings::pci_device_id { self.first } } /// Counts the number of parenthesis-delimited, comma-separated items. #[macro_export] macro_rules! count_paren_items { (($($item:tt)*), $($remaining:tt)*) => { 1 + $crate::count_paren_items!($($remaining)*) }; (($($item:tt)*)) => { 1 }; () => { 0 }; } #[macro_export] #[doc(hidden)] macro_rules! define_pci_id_array { ($($args:tt)*) => {{ const fn new<const N: usize>(ids: [$crate::pci::DeviceId; N]) -> $crate::pci::IdArray<N> { let mut raw_ids = [$crate::pci::DeviceId::ZERO; N]; let mut i = 0usize; while i < N { raw_ids[i] = ids[i].to_rawid(); i += 1; } $crate::pci::IdArray::<N>::new(raw_ids) } new([ $($args)* ]) }} } /// Define a const PCI device ID table. #[macro_export] macro_rules! define_pci_id_table { ([ $($args:tt)* ]) => { const ID_TABLE: $crate::pci::IdTable<'static> = { const ARRAY: $crate::pci::IdArray<{ $crate::count_paren_items!($($args)*) }> = $crate::define_pci_id_array!($($args)*); ARRAY.as_table() }; }; } pub use define_pci_id_table; /// Drivers must implement this trait to register a PCI driver. pub trait Driver { /// The table of device IDs supported by this driver. const ID_TABLE: IdTable<'static>; /// PCI driver probe. /// /// Called when a PCI device is matched against a PCI driver. fn probe(pdev: *mut bindings::pci_dev) -> Result; /// PCI driver remove. /// /// Called when the PCI device is unbound. fn remove(pdev: *mut bindings::pci_dev); } /// PCI abstraction for registering PCI drivers. pub struct Adapter<T: Driver>(PhantomData<T>); impl<T> Adapter<T> where T: Driver, { extern "C" fn probe( pdev: *mut bindings::pci_dev, _ent: *const bindings::pci_device_id, ) -> core::ffi::c_int { from_result(|| { T::probe(pdev)?; Ok(0) }) } extern "C" fn remove(pdev: *mut bindings::pci_dev) { T::remove(pdev); } } impl<T> driver::RegistrationOps for Adapter<T> where T: Driver, { type RegType = bindings::pci_driver; unsafe fn register( pdrv: *mut Self::RegType, name: &'static CStr, module: &'static ThisModule, ) -> Result { // SAFETY: By the safety requirements of this function `pdrv` is valid; we never move out // of `pdrv`. let pdrv = unsafe { &mut *pdrv }; pdrv.name = name.as_char_ptr(); pdrv.probe = Some(Self::probe); pdrv.remove = Some(Self::remove); pdrv.id_table = T::ID_TABLE.as_ref(); // SAFETY: `pdrv` is a valid `struct pci_driver`; `ThisModule` is equivalent to // C's `THIS_MODULE` and hence valid for `__pci_register_driver`. `name` is passed as `NULL` // terminated C string. // // Returns zero when the driver was registered successfully, a non-zero error code // otherwise, which is handled by `to_result`. to_result(unsafe { bindings::__pci_register_driver(pdrv, module.as_ptr(), name.as_char_ptr()) }) } unsafe fn unregister(pdrv: *mut Self::RegType) { // SAFETY: `pdrv` is guaranteed to be a valid `RegType`. unsafe { bindings::pci_unregister_driver(pdrv) } } }
// SPDX-License-Identifier: GPL-2.0 //! Wrappers for the PCI subsystem //! //! C header: [`include/linux/pci.h`](srctree/include/linux/pci.h) use core::marker::PhantomData; use kernel::{ bindings, driver, error::{from_result, to_result}, prelude::*, }; /// Abstraction for `bindings::pci_device_id`. #[derive(Clone, Copy)] pub struct DeviceId { /// Vendor ID pub vendor: u32, /// Device ID pub device: u32, /// Subsystem vendor ID pub subvendor: u32, /// Subsystem device ID pub subdevice: u32, /// Device class and subclass pub class: u32, /// Limit which sub-fields of the class pub class_mask: u32, } impl DeviceId { /// Zeroed `bindings::pci_device_id`. // SAFETY; The all-zero byte-pattern is valid for `bindings::pci_device_id`. pub const ZERO: bindings::pci_device_id = unsafe { core::mem::zeroed() }; const PCI_ANY_ID: u32 = !0; /// Equivalent to the PCI_DEVICE macro. pub const fn new(vendor: u32, device: u32) -> Self { Self { vendor, device, subvendor: DeviceId::PCI_ANY_ID, subdevice: DeviceId::PCI_ANY_ID, class: 0, class_mask: 0, } } /// Convert `DeviceId` to raw `bindings::pci_device_id`. pub const fn to_rawid(&self) -> bindings::pci_device_id { let mut raw = Self::ZERO; raw.vendor = self.vendor; raw.device = self.device; raw.subvendor = self.subvendor; raw.subdevice = self.subdevice; raw.class = self.class; raw.class_mask = self.class_mask; raw } } /// A zero-terminated PCI device ID array. #[repr(C)] pub struct IdArray<const N: usize> { ids: [bindings::pci_device_id; N], sentinel: bindings::pci_device_id, } impl<const N: usize> IdArray<N> { /// Creates a new instance of the ID array. /// /// The contents are derived from the given identifiers. #[doc(hidden)] pub const fn new(ids: [bindings::pci_device_id; N]) -> Self { Self { ids, sentinel: DeviceId::ZERO, } } /// Returns an `IdTable` backed by `self`. /// /// This is used to essentially erase the array size. pub const fn as_table(&self) -> IdTable<'_> { IdTable { first: &self.ids[0], } } } /// A device ID table. /// /// The table is guaranteed to be zero-terminated. #[repr(C)] pub struct IdTable<'a> { first: &'a bindings::pci_device_id, } impl AsRef<bindings::pci_device_id> for IdTable<'_> { fn as_ref(&self) -> &bindings::pci_device_id { self.first } } /// Counts the number of parenthesis-delimited, comma-separated items. #[macro_export] macro_rules! count_paren_items { (($($item:tt)*), $($remaining:tt)*) => { 1 + $crate::count_paren_items!($($remaining)*) }; (($($item:tt)*)) => { 1 }; () => { 0 }; } #[macro_export] #[doc(hidden)] macro_rules! define_pci_id_array { ($($args:tt)*) => {{ const fn new<const N: usize>(ids: [$crate::pci::DeviceId; N]) -> $crate::pci::IdArray<N> { let mut raw_ids = [$crate::pci::DeviceId::ZERO; N]; let mut i = 0usize; while i < N { raw_ids[i] = ids[i].to_rawid(); i += 1; } $crate::pci::IdArray::<N>::new(raw_ids) } new([ $($args)* ]) }} } /// Define a const PCI device ID table. #[macro_export] macro_rules! define_pci_id_table { ([ $($args:tt)* ]) => { const ID_TABLE: $crate::pci::IdTable<'static> = { const ARRAY: $crate::pci::IdArray<{ $crate::count_paren_items!($($args)*) }> = $crate::define_pci_id_array!($($args)*); ARRAY.as_table() }; }; } pub use define_pci_id_table; /// Drivers must implement this trait to register a PCI driver. pub trait Driver { /// The table of device IDs supported by this driver. const ID_TABLE: IdTable<'static>; /// PCI driver probe. /// /// Called when a PCI device is matched against a PCI driver. fn probe(pdev: *mut bindings::pci_dev) -> Result; /// PCI driver remove. /// /// Called when the PCI device is unbound. fn remove(pdev: *mut bindings::pci_dev); } /// PCI abstraction for registering PCI drivers. pub struct Adapter<T: Driver>(PhantomData<T>); impl<T> Adapter<T> where T: Driver, { extern "C" fn probe( pdev: *mut bindings::pci_dev, _ent: *const bindings::pci_device_id, ) -> core::ffi::c_int { from_result(|| { T::probe(pdev)?; Ok(0) }) } extern "C" fn remove(pdev: *mut bindings::pci_dev) { T::remove(pdev); } } impl<T> driver::RegistrationOps for Adapter<T> where T: Driver, { type RegType = bindings::pci_driver; unsafe fn register( pdrv: *mut Self::RegType, name: &'static CStr, module: &'static ThisModule, ) -> Result { // SAFETY: By the safety requirements of this function `pdrv` is valid; we never move out // of `pdrv`. let pdrv = unsafe { &mut *pdrv }; pdrv.name = name.as_char_ptr(); pdrv.probe = Some(Self::probe); pdrv.remove = Some(Self::remove); pdrv.id_table = T::ID_TABLE.as_ref(); // SAFETY: `pdrv` is a valid `struct pci_driver`; `ThisModule` is equivalent to // C's `THIS_MODULE` and hence valid for `__pci_register_driver`. `name` is passed as `NULL` // terminated C string. // // Returns zero when the driver was registered successfully, a non-zero error code // otherwise, which is handled by `to_result`. to_result(unsafe { bindings::__pci_register_driver(pdrv, module.as_ptr(), name.as_char_ptr()) }) } unsafe fn unregister(pdrv: *mut Self::RegType) { // SAFETY: `pdrv` is guaranteed to be a valid `RegType`. unsafe { bindings::pci_unregister_driver(pdrv) } } }
// SPDX-License-Identifier: GPL-2.0 //! Wrappers for the PCI subsystem //! //! C header: [`include/linux/pci.h`](srctree/include/linux/pci.h) use core::marker::PhantomData; use kernel::{ bindings, driver, error::{from_result, to_result}, prelude::*, }; /// Abstraction for `bindings::pci_device_id`. #[derive(Clone, Copy)] pub struct DeviceId { /// Vendor ID pub vendor: u32, /// Device ID pub device: u32, /// Subsystem vendor ID pub subvendor: u32, /// Subsystem device ID pub subdevice: u32, /// Device class and subclass pub class: u32, /// Limit which sub-fields of the class pub class_mask: u32, } impl DeviceId { /// Zeroed `bindings::pci_device_id`. // SAFETY; The all-zero byte-pattern is valid for `bindings::pci_device_id`. pub const ZERO: bindings::pci_device_id = unsafe { core::mem::zeroed() }; const PCI_ANY_ID: u32 = !0; /// Equivalent to the PCI_DEVICE macro. pub const fn new(vendor: u32, device: u32) -> Self { Self { vendor, device, subvendor: DeviceId::PCI_ANY_ID, subdevice: DeviceId::PCI_ANY_ID, class: 0, class_mask: 0, } } /// Convert `DeviceId` to raw `bindings::pci_device_id`. pub const fn to_rawid(&self) -> bindings::pci_device_id { let mut raw = Self::ZERO; raw.vendor = self.vendor; raw.device = self.device; raw.subvendor = self.subvendor; raw.subdevice = self.subdevice; raw.class = self.class; raw.class_mask = self.class_mask; raw } } /// A zero-terminated PCI device ID array. #[repr(C)] pub struct IdArray<const N: usize> { ids: [bindings::pci_device_id; N], sentinel: bindings::pci_device_id, } impl<const N: usize> IdArray<N> { /// Creates a new instance of the ID array. /// /// The contents are derived from the given identifiers. #[doc(hidden)] pub const fn new(ids: [bindings::pci_device_id; N]) -> Self { Self { ids, sentinel: DeviceId::ZERO, } } /// Returns an `IdTable` backed by `self`. /// /// This is used to essentially erase the array size. pub const fn as_table(&self) -> IdTable<'_> { IdTable { first: &self.ids[0], } } } /// A device ID table. /// /// The table is guaranteed to be zero-terminated. #[repr(C)] pub struct IdTable<'a> { first: &'a bindings::pci_device_id, } impl AsRef<bindings::pci_device_id> for IdTable<'_> { fn as_ref(&self) -> &bindings::pci_device_id { self.first } } /// Counts the number of parenthesis-delimited, comma-separated items. #[macro_export] macro_rules! count_paren_items { (($($item:tt)*), $($remaining:tt)*) => { 1 + $crate::count_paren_items!($($remaining)*) }; (($($item:tt)*)) => { 1 }; () => { 0 }; } #[macro_export] #[doc(hidden)] macro_rules! define_pci_id_array { ($($args:tt)*) => {{ const fn new<const N: usize>(ids: [$crate::pci::DeviceId; N]) -> $crate::pci::IdArray<N> { let mut raw_ids = [$crate::pci::DeviceId::ZERO; N]; let mut i = 0usize; while i < N { raw_ids[i] = ids[i].to_rawid(); i += 1; } $crate::pci::IdArray::<N>::new(raw_ids) } new([ $($args)* ]) }} } /// Define a const PCI device ID table. #[macro_export] macro_rules! define_pci_id_table { ([ $($args:tt)* ]) => { const ID_TABLE: $crate::pci::IdTable<'static> = { const ARRAY: $crate::pci::IdArray<{ $crate::count_paren_items!($($args)*) }> = $crate::define_pci_id_array!($($args)*); ARRAY.as_table() }; }; } pub use define_pci_id_table; /// Drivers must implement this trait to register a PCI driver. pub trait Driver { /// The table of device IDs supported by this driver. const ID_TABLE: IdTable<'static>; /// PCI driver probe. /// /// Called when a PCI device is matched against a PCI driver. fn probe(pdev: *mut bindings::pci_dev) -> Result; /// PCI driver remove. /// /// Called when the PCI device is unbound. fn remove(pdev: *mut bindings::pci_dev); } /// PCI abstraction for registering PCI drivers. pub struct Adapter<T: Driver>(PhantomData<T>); impl<T> Adapter<T> where T: Driver, { extern "C" fn probe( pdev: *mut bindings::pci_dev, _ent: *const bindings::pci_device_id, ) -> core::ffi::c_int { from_result(|| { T::probe(pdev)?; Ok(0) }) } extern "C" fn remove(pdev: *mut bindings::pci_dev) { T::remove(pdev); } } impl<T> driver::RegistrationOps for Adapter<T> where T: Driver, { type RegType = bindings::pci_driver; unsafe fn register( pdrv: *mut Self::RegType, name: &'static CStr, module: &'static ThisModule, ) -> Result { // SAFETY: By the safety requirements of this function `pdrv` is valid; we never move out // of `pdrv`. let pdrv = unsafe { &mut *pdrv }; pdrv.name = name.as_char_ptr(); pdrv.probe = Some(Self::probe); pdrv.remove = Some(Self::remove); pdrv.id_table = T::ID_TABLE.as_ref(); // SAFETY: `pdrv` is a valid `struct pci_driver`; `ThisModule` is equivalent to // C's `THIS_MODULE` and hence valid for `__pci_register_driver`. `name` is passed as `NULL` // terminated C string. // // Returns zero when the driver was registered successfully, a non-zero error code // otherwise, which is handled by `to_result`. to_result(unsafe { bindings::__pci_register_driver(pdrv, module.as_ptr(), name.as_char_ptr()) }) } unsafe fn unregister(pdrv: *mut Self::RegType) { // SAFETY: `pdrv` is guaranteed to be a valid `RegType`. unsafe { bindings::pci_unregister_driver(pdrv) } } }
samples/rust/rust_pci_driver/driver.rs
// SPDX-License-Identifier: GPL-2.0 //! Rust PCI driver sample use kernel::{bindings, pci, pci::define_pci_id_table, prelude::*}; const PCI_DEVICE_ID_REDHAT_QEMU_PCI_TESTDEV: u32 = 0x0005; pub(crate) struct Driver; impl pci::Driver for Driver { define_pci_id_table! { [ (pci::DeviceId::new(bindings::PCI_VENDOR_ID_REDHAT, PCI_DEVICE_ID_REDHAT_QEMU_PCI_TESTDEV)) ] } fn probe(_pdev: *mut bindings::pci_dev) -> Result { pr_info!("Probe Rust PCI driver sample.\n"); Ok(()) } fn remove(_pdev: *mut bindings::pci_dev) { pr_info!("Remove Rust PCI driver sample.\n"); } }
rust/kernel/pci.rs
// SPDX-License-Identifier: GPL-2.0 //! Wrappers for the PCI subsystem //! //! C header: [`include/linux/pci.h`](srctree/include/linux/pci.h) use core::marker::PhantomData; use kernel::{ bindings, driver, error::{from_result, to_result}, prelude::*, }; /// Abstraction for `bindings::pci_device_id`. #[derive(Clone, Copy)] pub struct DeviceId { /// Vendor ID pub vendor: u32, /// Device ID pub device: u32, /// Subsystem vendor ID pub subvendor: u32, /// Subsystem device ID pub subdevice: u32, /// Device class and subclass pub class: u32, /// Limit which sub-fields of the class pub class_mask: u32, } impl DeviceId { /// Zeroed `bindings::pci_device_id`. // SAFETY; The all-zero byte-pattern is valid for `bindings::pci_device_id`. pub const ZERO: bindings::pci_device_id = unsafe { core::mem::zeroed() }; const PCI_ANY_ID: u32 = !0; /// Equivalent to the PCI_DEVICE macro. pub const fn new(vendor: u32, device: u32) -> Self { Self { vendor, device, subvendor: DeviceId::PCI_ANY_ID, subdevice: DeviceId::PCI_ANY_ID, class: 0, class_mask: 0, } } /// Convert `DeviceId` to raw `bindings::pci_device_id`. /// /// `offset` is the offset of `ids[i]` to `id_infos[i]` within `IdArray`. pub const fn to_rawid(&self, offset: usize) -> bindings::pci_device_id { let mut raw = Self::ZERO; raw.vendor = self.vendor; raw.device = self.device; raw.subvendor = self.subvendor; raw.subdevice = self.subdevice; raw.class = self.class; raw.class_mask = self.class_mask; raw.driver_data = offset as _; raw } } /// A zero-terminated PCI device ID array. #[repr(C)] pub struct IdArray<U, const N: usize> { ids: [bindings::pci_device_id; N], sentinel: bindings::pci_device_id, id_infos: [Option<U>; N], } impl<U, const N: usize> IdArray<U, N> { /// Creates a new instance of the ID array. /// /// The contents are derived from the given identifiers. #[doc(hidden)] pub const fn new(ids: [bindings::pci_device_id; N], infos: [Option<U>; N]) -> Self { Self { ids, sentinel: DeviceId::ZERO, id_infos: infos, } } /// Returns an `IdTable` backed by `self`. /// /// This is used to essentially erase the array size. pub const fn as_table(&self) -> IdTable<'_, U> { IdTable { first: &self.ids[0], _p: PhantomData, } } /// Returns the offset of `ids[i]` to `id_infos[i]` within `IdArray`. #[doc(hidden)] pub const fn get_offset(index: usize) -> usize { let id_size = core::mem::size_of::<bindings::pci_device_id>(); let info_size = core::mem::size_of::<Option<U>>(); id_size * (N - index + 1) + info_size * index } } /// A device ID table. /// /// The table is guaranteed to be zero-terminated. #[repr(C)] pub struct IdTable<'a, U> { first: &'a bindings::pci_device_id, _p: PhantomData<&'a U>, } impl<U> AsRef<bindings::pci_device_id> for IdTable<'_, U> { fn as_ref(&self) -> &bindings::pci_device_id { self.first } } /// Converts a comma-separated list of pairs into an array with the first element. That is, it /// discards the second element of the pair. /// /// Additionally, it automatically introduces a type if the first element is warpped in curly /// braces, for example, if it's `{v: 10}`, it becomes `X { v: 10 }`; this is to avoid repeating /// the type. #[macro_export] macro_rules! first_item { ($id_type:ty, $(({$($first:tt)*}, $second:expr)),* $(,)?) => { { type IdType = $id_type; [$(IdType{$($first)*},)*] } }; ($id_type:ty, $(($first:expr, $second:expr)),* $(,)?) => { [$($first,)*] }; } /// Converts a comma-separated list of pairs into an array with the second element. That is, it /// discards the first element of the pair. #[macro_export] macro_rules! second_item { ($(({$($first:tt)*}, $second:expr)),* $(,)?) => { [$($second,)*] }; ($(($first:expr, $second:expr)),* $(,)?) => { [$($second,)*] }; } /// Counts the number of parenthesis-delimited, comma-separated items. #[macro_export] macro_rules! count_paren_items { (($($item:tt)*), $($remaining:tt)*) => { 1 + $crate::count_paren_items!($($remaining)*) }; (($($item:tt)*)) => { 1 }; () => { 0 }; } #[macro_export] #[doc(hidden)] macro_rules! define_pci_id_array { ($id_type:ty, $($args:tt)*) => {{ const fn new<U, const N: usize>( ids: [$crate::pci::DeviceId; N], infos: [Option<U>; N]) -> $crate::pci::IdArray<U, N> { let mut raw_ids = [$crate::pci::DeviceId::ZERO; N]; // The offset of `ids[i]` to `id_infos[i]` within `IdArray`. let mut i = 0usize; while i < N { let offset = $crate::pci::IdArray::<U, N>::get_offset(i); raw_ids[i] = ids[i].to_rawid(offset); i += 1; } $crate::pci::IdArray::<U, N>::new(raw_ids, infos) } new($crate::first_item!($id_type, $($args)*), $crate::second_item!($($args)*)) }} } /// Define a const PCI device ID table. #[macro_export] macro_rules! define_pci_id_table { ($id_type:ty, [ $($args:tt)* ]) => { type IdInfo = $id_type; const ID_TABLE: $crate::pci::IdTable<'static, $id_type> = { const ARRAY: $crate::pci::IdArray<$id_type, { $crate::count_paren_items!($($args)*) }> = $crate::define_pci_id_array!($id_type, $($args)*); ARRAY.as_table() }; }; } pub use define_pci_id_table; /// Drivers must implement this trait to register a PCI driver. pub trait Driver { /// The type holding information about each device ID supported by the drivID. type IdInfo: 'static; /// The table of device IDs supported by this driver. const ID_TABLE: IdTable<'static, Self::IdInfo>; /// PCI driver probe. /// /// Called when a PCI device is matched against a PCI driver. fn probe(pdev: *mut bindings::pci_dev, id: Option<&Self::IdInfo>) -> Result; /// PCI driver remove. /// /// Called when the PCI device is unbound. fn remove(pdev: *mut bindings::pci_dev); } /// PCI abstraction for registering PCI drivers. pub struct Adapter<T: Driver>(PhantomData<T>); impl<T> Adapter<T> where T: Driver, { extern "C" fn probe( pdev: *mut bindings::pci_dev, id: *const bindings::pci_device_id, ) -> core::ffi::c_int { // SAFETY: `id` is a pointer within the static table, so it's always valid. let offset = unsafe { (*id).driver_data }; let info = { // SAFETY: The offset comes from a previous call to `offset_from` in `IdArray::new`, // which guarantees that the resulting pointer is within the table. let ptr = unsafe { id.cast::<u8>() .offset(offset as _) .cast::<Option<T::IdInfo>>() }; // SAFETY: Guaranteed by the preceding safety requirement. unsafe { (*ptr).as_ref() } }; from_result(|| { T::probe(pdev, info)?; Ok(0) }) } extern "C" fn remove(pdev: *mut bindings::pci_dev) { T::remove(pdev); } } impl<T> driver::RegistrationOps for Adapter<T> where T: Driver, { type RegType = bindings::pci_driver; unsafe fn register( pdrv: *mut Self::RegType, name: &'static CStr, module: &'static ThisModule, ) -> Result { // SAFETY: By the safety requirements of this function `pdrv` is valid; we never move out // of `pdrv`. let pdrv = unsafe { &mut *pdrv }; pdrv.name = name.as_char_ptr(); pdrv.probe = Some(Self::probe); pdrv.remove = Some(Self::remove); pdrv.id_table = T::ID_TABLE.as_ref(); // SAFETY: `pdrv` is a valid `struct pci_driver`; `ThisModule` is equivalent to // C's `THIS_MODULE` and hence valid for `__pci_register_driver`. `name` is passed as `NULL` // terminated C string. // // Returns zero when the driver was registered successfully, a non-zero error code // otherwise, which is handled by `to_result`. to_result(unsafe { bindings::__pci_register_driver(pdrv, module.as_ptr(), name.as_char_ptr()) }) } unsafe fn unregister(pdrv: *mut Self::RegType) { // SAFETY: `pdrv` is guaranteed to be a valid `RegType`. unsafe { bindings::pci_unregister_driver(pdrv) } } }
// SPDX-License-Identifier: GPL-2.0 //! Wrappers for the PCI subsystem //! //! C header: [`include/linux/pci.h`](srctree/include/linux/pci.h) use core::marker::PhantomData; use kernel::{ bindings, driver, error::{from_result, to_result}, prelude::*, }; /// Abstraction for `bindings::pci_device_id`. #[derive(Clone, Copy)] pub struct DeviceId { /// Vendor ID pub vendor: u32, /// Device ID pub device: u32, /// Subsystem vendor ID pub subvendor: u32, /// Subsystem device ID pub subdevice: u32, /// Device class and subclass pub class: u32, /// Limit which sub-fields of the class pub class_mask: u32, } impl DeviceId { /// Zeroed `bindings::pci_device_id`. // SAFETY; The all-zero byte-pattern is valid for `bindings::pci_device_id`. pub const ZERO: bindings::pci_device_id = unsafe { core::mem::zeroed() }; const PCI_ANY_ID: u32 = !0; /// Equivalent to the PCI_DEVICE macro. pub const fn new(vendor: u32, device: u32) -> Self { Self { vendor, device, subvendor: DeviceId::PCI_ANY_ID, subdevice: DeviceId::PCI_ANY_ID, class: 0, class_mask: 0, } } /// Convert `DeviceId` to raw `bindings::pci_device_id`. /// /// `offset` is the offset of `ids[i]` to `id_infos[i]` within `IdArray`. pub const fn to_rawid(&self, offset: usize) -> bindings::pci_device_id { let mut raw = Self::ZERO; raw.vendor = self.vendor; raw.device = self.device; raw.subvendor = self.subvendor; raw.subdevice = self.subdevice; raw.class = self.class; raw.class_mask = self.class_mask; raw.driver_data = offset as _; raw } } /// A zero-terminated PCI device ID array. #[repr(C)] pub struct IdArray<U, const N: usize> { ids: [bindings::pci_device_id; N], sentinel: bindings::pci_device_id, id_infos: [Option<U>; N], } impl<U, const N: usize> IdArray<U, N> { /// Creates a new instance of the ID array. /// /// The contents are derived from the given identifiers. #[doc(hidden)] pub const fn new(ids: [bindings::pci_device_id; N], infos: [Option<U>; N]) -> Self { Self { ids, sentinel: DeviceId::ZERO, id_infos: infos, } } /// Returns an `IdTable` backed by `self`. /// /// This is used to essentially erase the array size. pub const fn as_table(&self) -> IdTable<'_, U> { IdTable { first: &self.ids[0], _p: PhantomData, } } /// Returns the offset of `ids[i]` to `id_infos[i]` within `IdArray`. #[doc(hidden)] pub const fn get_offset(index: usize) -> usize { let id_size = core::mem::size_of::<bindings::pci_device_id>(); let info_size = core::mem::size_of::<Option<U>>(); id_size * (N - index + 1) + info_size * index } } /// A device ID table. /// /// The table is guaranteed to be zero-terminated. #[repr(C)] pub struct IdTable<'a, U> { first: &'a bindings::pci_device_id, _p: PhantomData<&'a U>, } impl<U> AsRef<bindings::pci_device_id> for IdTable<'_, U> { fn as_ref(&self) -> &bindings::pci_device_id { self.first } } /// Converts a comma-separated list of pairs into an array with the first element. That is, it /// discards the second element of the pair. /// /// Additionally, it automatically introduces a type if the first element is warpped in curly /// braces, for example, if it's `{v: 10}`, it becomes `X { v: 10 }`; this is to avoid repeating /// the type. #[macro_export] macro_rules! first_item { ($id_type:ty, $(({$($first:tt)*}, $second:expr)),* $(,)?) => { { type IdType = $id_type; [$(IdType{$($first)*},)*] } }; ($id_type:ty, $(($first:expr, $second:expr)),* $(,)?) => { [$($first,)*] }; } /// Converts a comma-separated list of pairs into an array with the second element. That is, it /// discards the first element of the pair. #[macro_export] macro_rules! second_item { ($(({$($first:tt)*}, $second:expr)),* $(,)?) => { [$($second,)*] }; ($(($first:expr, $second:expr)),* $(,)?) => { [$($second,)*] }; } /// Counts the number of parenthesis-delimited, comma-separated items. #[macro_export] macro_rules! count_paren_items { (($($item:tt)*), $($remaining:tt)*) => { 1 + $crate::count_paren_items!($($remaining)*) }; (($($item:tt)*)) => { 1 }; () => { 0 }; } #[macro_export] #[doc(hidden)] macro_rules! define_pci_id_array { ($id_type:ty, $($args:tt)*) => {{ const fn new<U, const N: usize>( ids: [$crate::pci::DeviceId; N], infos: [Option<U>; N]) -> $crate::pci::IdArray<U, N> { let mut raw_ids = [$crate::pci::DeviceId::ZERO; N]; // The offset of `ids[i]` to `id_infos[i]` within `IdArray`. let mut i = 0usize; while i < N { let offset = $crate::pci::IdArray::<U, N>::get_offset(i); raw_ids[i] = ids[i].to_rawid(offset); i += 1; } $crate::pci::IdArray::<U, N>::new(raw_ids, infos) } new($crate::first_item!($id_type, $($args)*), $crate::second_item!($($args)*)) }} } /// Define a const PCI device ID table. #[macro_export] macro_rules! define_pci_id_table { ($id_type:ty, [ $($args:tt)* ]) => { type IdInfo = $id_type; const ID_TABLE: $crate::pci::IdTable<'static, $id_type> = { const ARRAY: $crate::pci::IdArray<$id_type, { $crate::count_paren_items!($($args)*) }> = $crate::define_pci_id_array!($id_type, $($args)*); ARRAY.as_table() }; }; } pub use define_pci_id_table; /// Drivers must implement this trait to register a PCI driver. pub trait Driver { /// The type holding information about each device ID supported by the drivID. type IdInfo: 'static; /// The table of device IDs supported by this driver. const ID_TABLE: IdTable<'static, Self::IdInfo>; /// PCI driver probe. /// /// Called when a PCI device is matched against a PCI driver. fn probe(pdev: *mut bindings::pci_dev, id: Option<&Self::IdInfo>) -> Result; /// PCI driver remove. /// /// Called when the PCI device is unbound. fn remove(pdev: *mut bindings::pci_dev); } /// PCI abstraction for registering PCI drivers. pub struct Adapter<T: Driver>(PhantomData<T>); impl<T> Adapter<T> where T: Driver, { extern "C" fn probe( pdev: *mut bindings::pci_dev, id: *const bindings::pci_device_id, ) -> core::ffi::c_int { // SAFETY: `id` is a pointer within the static table, so it's always valid. let offset = unsafe { (*id).driver_data }; let info = { // SAFETY: The offset comes from a previous call to `offset_from` in `IdArray::new`, // which guarantees that the resulting pointer is within the table. let ptr = unsafe { id.cast::<u8>() .offset(offset as _) .cast::<Option<T::IdInfo>>() }; // SAFETY: Guaranteed by the preceding safety requirement. unsafe { (*ptr).as_ref() } }; from_result(|| { T::probe(pdev, info)?; Ok(0) }) } extern "C" fn remove(pdev: *mut bindings::pci_dev) { T::remove(pdev); } } impl<T> driver::RegistrationOps for Adapter<T> where T: Driver, { type RegType = bindings::pci_driver; unsafe fn register( pdrv: *mut Self::RegType, name: &'static CStr, module: &'static ThisModule, ) -> Result { // SAFETY: By the safety requirements of this function `pdrv` is valid; we never move out // of `pdrv`. let pdrv = unsafe { &mut *pdrv }; pdrv.name = name.as_char_ptr(); pdrv.probe = Some(Self::probe); pdrv.remove = Some(Self::remove); pdrv.id_table = T::ID_TABLE.as_ref(); // SAFETY: `pdrv` is a valid `struct pci_driver`; `ThisModule` is equivalent to // C's `THIS_MODULE` and hence valid for `__pci_register_driver`. `name` is passed as `NULL` // terminated C string. // // Returns zero when the driver was registered successfully, a non-zero error code // otherwise, which is handled by `to_result`. to_result(unsafe { bindings::__pci_register_driver(pdrv, module.as_ptr(), name.as_char_ptr()) }) } unsafe fn unregister(pdrv: *mut Self::RegType) { // SAFETY: `pdrv` is guaranteed to be a valid `RegType`. unsafe { bindings::pci_unregister_driver(pdrv) } } }
// SPDX-License-Identifier: GPL-2.0 //! Wrappers for the PCI subsystem //! //! C header: [`include/linux/pci.h`](srctree/include/linux/pci.h) use core::marker::PhantomData; use kernel::{ bindings, driver, error::{from_result, to_result}, prelude::*, }; /// Abstraction for `bindings::pci_device_id`. #[derive(Clone, Copy)] pub struct DeviceId { /// Vendor ID pub vendor: u32, /// Device ID pub device: u32, /// Subsystem vendor ID pub subvendor: u32, /// Subsystem device ID pub subdevice: u32, /// Device class and subclass pub class: u32, /// Limit which sub-fields of the class pub class_mask: u32, } impl DeviceId { /// Zeroed `bindings::pci_device_id`. // SAFETY; The all-zero byte-pattern is valid for `bindings::pci_device_id`. pub const ZERO: bindings::pci_device_id = unsafe { core::mem::zeroed() }; const PCI_ANY_ID: u32 = !0; /// Equivalent to the PCI_DEVICE macro. pub const fn new(vendor: u32, device: u32) -> Self { Self { vendor, device, subvendor: DeviceId::PCI_ANY_ID, subdevice: DeviceId::PCI_ANY_ID, class: 0, class_mask: 0, } } /// Convert `DeviceId` to raw `bindings::pci_device_id`. /// /// `offset` is the offset of `ids[i]` to `id_infos[i]` within `IdArray`. pub const fn to_rawid(&self, offset: usize) -> bindings::pci_device_id { let mut raw = Self::ZERO; raw.vendor = self.vendor; raw.device = self.device; raw.subvendor = self.subvendor; raw.subdevice = self.subdevice; raw.class = self.class; raw.class_mask = self.class_mask; raw.driver_data = offset as _; raw } } /// A zero-terminated PCI device ID array. #[repr(C)] pub struct IdArray<U, const N: usize> { ids: [bindings::pci_device_id; N], sentinel: bindings::pci_device_id, id_infos: [Option<U>; N], } impl<U, const N: usize> IdArray<U, N> { /// Creates a new instance of the ID array. /// /// The contents are derived from the given identifiers. #[doc(hidden)] pub const fn new(ids: [bindings::pci_device_id; N], infos: [Option<U>; N]) -> Self { Self { ids, sentinel: DeviceId::ZERO, id_infos: infos, } } /// Returns an `IdTable` backed by `self`. /// /// This is used to essentially erase the array size. pub const fn as_table(&self) -> IdTable<'_, U> { IdTable { first: &self.ids[0], _p: PhantomData, } } /// Returns the offset of `ids[i]` to `id_infos[i]` within `IdArray`. #[doc(hidden)] pub const fn get_offset(index: usize) -> usize { let id_size = core::mem::size_of::<bindings::pci_device_id>(); let info_size = core::mem::size_of::<Option<U>>(); id_size * (N - index + 1) + info_size * index } } /// A device ID table. /// /// The table is guaranteed to be zero-terminated. #[repr(C)] pub struct IdTable<'a, U> { first: &'a bindings::pci_device_id, _p: PhantomData<&'a U>, } impl<U> AsRef<bindings::pci_device_id> for IdTable<'_, U> { fn as_ref(&self) -> &bindings::pci_device_id { self.first } } /// Converts a comma-separated list of pairs into an array with the first element. That is, it /// discards the second element of the pair. /// /// Additionally, it automatically introduces a type if the first element is warpped in curly /// braces, for example, if it's `{v: 10}`, it becomes `X { v: 10 }`; this is to avoid repeating /// the type. #[macro_export] macro_rules! first_item { ($id_type:ty, $(({$($first:tt)*}, $second:expr)),* $(,)?) => { { type IdType = $id_type; [$(IdType{$($first)*},)*] } }; ($id_type:ty, $(($first:expr, $second:expr)),* $(,)?) => { [$($first,)*] }; } /// Converts a comma-separated list of pairs into an array with the second element. That is, it /// discards the first element of the pair. #[macro_export] macro_rules! second_item { ($(({$($first:tt)*}, $second:expr)),* $(,)?) => { [$($second,)*] }; ($(($first:expr, $second:expr)),* $(,)?) => { [$($second,)*] }; } /// Counts the number of parenthesis-delimited, comma-separated items. #[macro_export] macro_rules! count_paren_items { (($($item:tt)*), $($remaining:tt)*) => { 1 + $crate::count_paren_items!($($remaining)*) }; (($($item:tt)*)) => { 1 }; () => { 0 }; } #[macro_export] #[doc(hidden)] macro_rules! define_pci_id_array { ($id_type:ty, $($args:tt)*) => {{ const fn new<U, const N: usize>( ids: [$crate::pci::DeviceId; N], infos: [Option<U>; N]) -> $crate::pci::IdArray<U, N> { let mut raw_ids = [$crate::pci::DeviceId::ZERO; N]; // The offset of `ids[i]` to `id_infos[i]` within `IdArray`. let mut i = 0usize; while i < N { let offset = $crate::pci::IdArray::<U, N>::get_offset(i); raw_ids[i] = ids[i].to_rawid(offset); i += 1; } $crate::pci::IdArray::<U, N>::new(raw_ids, infos) } new($crate::first_item!($id_type, $($args)*), $crate::second_item!($($args)*)) }} } /// Define a const PCI device ID table. #[macro_export] macro_rules! define_pci_id_table { ($id_type:ty, [ $($args:tt)* ]) => { type IdInfo = $id_type; const ID_TABLE: $crate::pci::IdTable<'static, $id_type> = { const ARRAY: $crate::pci::IdArray<$id_type, { $crate::count_paren_items!($($args)*) }> = $crate::define_pci_id_array!($id_type, $($args)*); ARRAY.as_table() }; }; } pub use define_pci_id_table; /// Drivers must implement this trait to register a PCI driver. pub trait Driver { /// The type holding information about each device ID supported by the drivID. type IdInfo: 'static; /// The table of device IDs supported by this driver. const ID_TABLE: IdTable<'static, Self::IdInfo>; /// PCI driver probe. /// /// Called when a PCI device is matched against a PCI driver. fn probe(pdev: *mut bindings::pci_dev, id: Option<&Self::IdInfo>) -> Result; /// PCI driver remove. /// /// Called when the PCI device is unbound. fn remove(pdev: *mut bindings::pci_dev); } /// PCI abstraction for registering PCI drivers. pub struct Adapter<T: Driver>(PhantomData<T>); impl<T> Adapter<T> where T: Driver, { extern "C" fn probe( pdev: *mut bindings::pci_dev, id: *const bindings::pci_device_id, ) -> core::ffi::c_int { // SAFETY: `id` is a pointer within the static table, so it's always valid. let offset = unsafe { (*id).driver_data }; let info = { // SAFETY: The offset comes from a previous call to `offset_from` in `IdArray::new`, // which guarantees that the resulting pointer is within the table. let ptr = unsafe { id.cast::<u8>() .offset(offset as _) .cast::<Option<T::IdInfo>>() }; // SAFETY: Guaranteed by the preceding safety requirement. unsafe { (*ptr).as_ref() } }; from_result(|| { T::probe(pdev, info)?; Ok(0) }) } extern "C" fn remove(pdev: *mut bindings::pci_dev) { T::remove(pdev); } } impl<T> driver::RegistrationOps for Adapter<T> where T: Driver, { type RegType = bindings::pci_driver; unsafe fn register( pdrv: *mut Self::RegType, name: &'static CStr, module: &'static ThisModule, ) -> Result { // SAFETY: By the safety requirements of this function `pdrv` is valid; we never move out // of `pdrv`. let pdrv = unsafe { &mut *pdrv }; pdrv.name = name.as_char_ptr(); pdrv.probe = Some(Self::probe); pdrv.remove = Some(Self::remove); pdrv.id_table = T::ID_TABLE.as_ref(); // SAFETY: `pdrv` is a valid `struct pci_driver`; `ThisModule` is equivalent to // C's `THIS_MODULE` and hence valid for `__pci_register_driver`. `name` is passed as `NULL` // terminated C string. // // Returns zero when the driver was registered successfully, a non-zero error code // otherwise, which is handled by `to_result`. to_result(unsafe { bindings::__pci_register_driver(pdrv, module.as_ptr(), name.as_char_ptr()) }) } unsafe fn unregister(pdrv: *mut Self::RegType) { // SAFETY: `pdrv` is guaranteed to be a valid `RegType`. unsafe { bindings::pci_unregister_driver(pdrv) } } }
// SPDX-License-Identifier: GPL-2.0 //! Wrappers for the PCI subsystem //! //! C header: [`include/linux/pci.h`](srctree/include/linux/pci.h) use core::marker::PhantomData; use kernel::{ bindings, driver, error::{from_result, to_result}, prelude::*, }; /// Abstraction for `bindings::pci_device_id`. #[derive(Clone, Copy)] pub struct DeviceId { /// Vendor ID pub vendor: u32, /// Device ID pub device: u32, /// Subsystem vendor ID pub subvendor: u32, /// Subsystem device ID pub subdevice: u32, /// Device class and subclass pub class: u32, /// Limit which sub-fields of the class pub class_mask: u32, } impl DeviceId { /// Zeroed `bindings::pci_device_id`. // SAFETY; The all-zero byte-pattern is valid for `bindings::pci_device_id`. pub const ZERO: bindings::pci_device_id = unsafe { core::mem::zeroed() }; const PCI_ANY_ID: u32 = !0; /// Equivalent to the PCI_DEVICE macro. pub const fn new(vendor: u32, device: u32) -> Self { Self { vendor, device, subvendor: DeviceId::PCI_ANY_ID, subdevice: DeviceId::PCI_ANY_ID, class: 0, class_mask: 0, } } /// Convert `DeviceId` to raw `bindings::pci_device_id`. /// /// `offset` is the offset of `ids[i]` to `id_infos[i]` within `IdArray`. pub const fn to_rawid(&self, offset: usize) -> bindings::pci_device_id { let mut raw = Self::ZERO; raw.vendor = self.vendor; raw.device = self.device; raw.subvendor = self.subvendor; raw.subdevice = self.subdevice; raw.class = self.class; raw.class_mask = self.class_mask; raw.driver_data = offset as _; raw } } /// A zero-terminated PCI device ID array. #[repr(C)] pub struct IdArray<U, const N: usize> { ids: [bindings::pci_device_id; N], sentinel: bindings::pci_device_id, id_infos: [Option<U>; N], } impl<U, const N: usize> IdArray<U, N> { /// Creates a new instance of the ID array. /// /// The contents are derived from the given identifiers. #[doc(hidden)] pub const fn new(ids: [bindings::pci_device_id; N], infos: [Option<U>; N]) -> Self { Self { ids, sentinel: DeviceId::ZERO, id_infos: infos, } } /// Returns an `IdTable` backed by `self`. /// /// This is used to essentially erase the array size. pub const fn as_table(&self) -> IdTable<'_, U> { IdTable { first: &self.ids[0], _p: PhantomData, } } /// Returns the offset of `ids[i]` to `id_infos[i]` within `IdArray`. #[doc(hidden)] pub const fn get_offset(index: usize) -> usize { let id_size = core::mem::size_of::<bindings::pci_device_id>(); let info_size = core::mem::size_of::<Option<U>>(); id_size * (N - index + 1) + info_size * index } } /// A device ID table. /// /// The table is guaranteed to be zero-terminated. #[repr(C)] pub struct IdTable<'a, U> { first: &'a bindings::pci_device_id, _p: PhantomData<&'a U>, } impl<U> AsRef<bindings::pci_device_id> for IdTable<'_, U> { fn as_ref(&self) -> &bindings::pci_device_id { self.first } } /// Converts a comma-separated list of pairs into an array with the first element. That is, it /// discards the second element of the pair. /// /// Additionally, it automatically introduces a type if the first element is warpped in curly /// braces, for example, if it's `{v: 10}`, it becomes `X { v: 10 }`; this is to avoid repeating /// the type. #[macro_export] macro_rules! first_item { ($id_type:ty, $(({$($first:tt)*}, $second:expr)),* $(,)?) => { { type IdType = $id_type; [$(IdType{$($first)*},)*] } }; ($id_type:ty, $(($first:expr, $second:expr)),* $(,)?) => { [$($first,)*] }; } /// Converts a comma-separated list of pairs into an array with the second element. That is, it /// discards the first element of the pair. #[macro_export] macro_rules! second_item { ($(({$($first:tt)*}, $second:expr)),* $(,)?) => { [$($second,)*] }; ($(($first:expr, $second:expr)),* $(,)?) => { [$($second,)*] }; } /// Counts the number of parenthesis-delimited, comma-separated items. #[macro_export] macro_rules! count_paren_items { (($($item:tt)*), $($remaining:tt)*) => { 1 + $crate::count_paren_items!($($remaining)*) }; (($($item:tt)*)) => { 1 }; () => { 0 }; } #[macro_export] #[doc(hidden)] macro_rules! define_pci_id_array { ($id_type:ty, $($args:tt)*) => {{ const fn new<U, const N: usize>( ids: [$crate::pci::DeviceId; N], infos: [Option<U>; N]) -> $crate::pci::IdArray<U, N> { let mut raw_ids = [$crate::pci::DeviceId::ZERO; N]; // The offset of `ids[i]` to `id_infos[i]` within `IdArray`. let mut i = 0usize; while i < N { let offset = $crate::pci::IdArray::<U, N>::get_offset(i); raw_ids[i] = ids[i].to_rawid(offset); i += 1; } $crate::pci::IdArray::<U, N>::new(raw_ids, infos) } new($crate::first_item!($id_type, $($args)*), $crate::second_item!($($args)*)) }} } /// Define a const PCI device ID table. #[macro_export] macro_rules! define_pci_id_table { ($id_type:ty, [ $($args:tt)* ]) => { type IdInfo = $id_type; const ID_TABLE: $crate::pci::IdTable<'static, $id_type> = { const ARRAY: $crate::pci::IdArray<$id_type, { $crate::count_paren_items!($($args)*) }> = $crate::define_pci_id_array!($id_type, $($args)*); ARRAY.as_table() }; }; } pub use define_pci_id_table; /// Drivers must implement this trait to register a PCI driver. pub trait Driver { /// The type holding information about each device ID supported by the drivID. type IdInfo: 'static; /// The table of device IDs supported by this driver. const ID_TABLE: IdTable<'static, Self::IdInfo>; /// PCI driver probe. /// /// Called when a PCI device is matched against a PCI driver. fn probe(pdev: *mut bindings::pci_dev, id: Option<&Self::IdInfo>) -> Result; /// PCI driver remove. /// /// Called when the PCI device is unbound. fn remove(pdev: *mut bindings::pci_dev); } /// PCI abstraction for registering PCI drivers. pub struct Adapter<T: Driver>(PhantomData<T>); impl<T> Adapter<T> where T: Driver, { extern "C" fn probe( pdev: *mut bindings::pci_dev, id: *const bindings::pci_device_id, ) -> core::ffi::c_int { // SAFETY: `id` is a pointer within the static table, so it's always valid. let offset = unsafe { (*id).driver_data }; let info = { // SAFETY: The offset comes from a previous call to `offset_from` in `IdArray::new`, // which guarantees that the resulting pointer is within the table. let ptr = unsafe { id.cast::<u8>() .offset(offset as _) .cast::<Option<T::IdInfo>>() }; // SAFETY: Guaranteed by the preceding safety requirement. unsafe { (*ptr).as_ref() } }; from_result(|| { T::probe(pdev, info)?; Ok(0) }) } extern "C" fn remove(pdev: *mut bindings::pci_dev) { T::remove(pdev); } } impl<T> driver::RegistrationOps for Adapter<T> where T: Driver, { type RegType = bindings::pci_driver; unsafe fn register( pdrv: *mut Self::RegType, name: &'static CStr, module: &'static ThisModule, ) -> Result { // SAFETY: By the safety requirements of this function `pdrv` is valid; we never move out // of `pdrv`. let pdrv = unsafe { &mut *pdrv }; pdrv.name = name.as_char_ptr(); pdrv.probe = Some(Self::probe); pdrv.remove = Some(Self::remove); pdrv.id_table = T::ID_TABLE.as_ref(); // SAFETY: `pdrv` is a valid `struct pci_driver`; `ThisModule` is equivalent to // C's `THIS_MODULE` and hence valid for `__pci_register_driver`. `name` is passed as `NULL` // terminated C string. // // Returns zero when the driver was registered successfully, a non-zero error code // otherwise, which is handled by `to_result`. to_result(unsafe { bindings::__pci_register_driver(pdrv, module.as_ptr(), name.as_char_ptr()) }) } unsafe fn unregister(pdrv: *mut Self::RegType) { // SAFETY: `pdrv` is guaranteed to be a valid `RegType`. unsafe { bindings::pci_unregister_driver(pdrv) } } }
// SPDX-License-Identifier: GPL-2.0 //! Wrappers for the PCI subsystem //! //! C header: [`include/linux/pci.h`](srctree/include/linux/pci.h) use core::marker::PhantomData; use kernel::{ bindings, driver, error::{from_result, to_result}, prelude::*, }; /// Abstraction for `bindings::pci_device_id`. #[derive(Clone, Copy)] pub struct DeviceId { /// Vendor ID pub vendor: u32, /// Device ID pub device: u32, /// Subsystem vendor ID pub subvendor: u32, /// Subsystem device ID pub subdevice: u32, /// Device class and subclass pub class: u32, /// Limit which sub-fields of the class pub class_mask: u32, } impl DeviceId { /// Zeroed `bindings::pci_device_id`. // SAFETY; The all-zero byte-pattern is valid for `bindings::pci_device_id`. pub const ZERO: bindings::pci_device_id = unsafe { core::mem::zeroed() }; const PCI_ANY_ID: u32 = !0; /// Equivalent to the PCI_DEVICE macro. pub const fn new(vendor: u32, device: u32) -> Self { Self { vendor, device, subvendor: DeviceId::PCI_ANY_ID, subdevice: DeviceId::PCI_ANY_ID, class: 0, class_mask: 0, } } /// Convert `DeviceId` to raw `bindings::pci_device_id`. /// /// `offset` is the offset of `ids[i]` to `id_infos[i]` within `IdArray`. pub const fn to_rawid(&self, offset: usize) -> bindings::pci_device_id { let mut raw = Self::ZERO; raw.vendor = self.vendor; raw.device = self.device; raw.subvendor = self.subvendor; raw.subdevice = self.subdevice; raw.class = self.class; raw.class_mask = self.class_mask; raw.driver_data = offset as _; raw } } /// A zero-terminated PCI device ID array. #[repr(C)] pub struct IdArray<U, const N: usize> { ids: [bindings::pci_device_id; N], sentinel: bindings::pci_device_id, id_infos: [Option<U>; N], } impl<U, const N: usize> IdArray<U, N> { /// Creates a new instance of the ID array. /// /// The contents are derived from the given identifiers. #[doc(hidden)] pub const fn new(ids: [bindings::pci_device_id; N], infos: [Option<U>; N]) -> Self { Self { ids, sentinel: DeviceId::ZERO, id_infos: infos, } } /// Returns an `IdTable` backed by `self`. /// /// This is used to essentially erase the array size. pub const fn as_table(&self) -> IdTable<'_, U> { IdTable { first: &self.ids[0], _p: PhantomData, } } /// Returns the offset of `ids[i]` to `id_infos[i]` within `IdArray`. #[doc(hidden)] pub const fn get_offset(index: usize) -> usize { let id_size = core::mem::size_of::<bindings::pci_device_id>(); let info_size = core::mem::size_of::<Option<U>>(); id_size * (N - index + 1) + info_size * index } } /// A device ID table. /// /// The table is guaranteed to be zero-terminated. #[repr(C)] pub struct IdTable<'a, U> { first: &'a bindings::pci_device_id, _p: PhantomData<&'a U>, } impl<U> AsRef<bindings::pci_device_id> for IdTable<'_, U> { fn as_ref(&self) -> &bindings::pci_device_id { self.first } } /// Converts a comma-separated list of pairs into an array with the first element. That is, it /// discards the second element of the pair. /// /// Additionally, it automatically introduces a type if the first element is warpped in curly /// braces, for example, if it's `{v: 10}`, it becomes `X { v: 10 }`; this is to avoid repeating /// the type. #[macro_export] macro_rules! first_item { ($id_type:ty, $(({$($first:tt)*}, $second:expr)),* $(,)?) => { { type IdType = $id_type; [$(IdType{$($first)*},)*] } }; ($id_type:ty, $(($first:expr, $second:expr)),* $(,)?) => { [$($first,)*] }; } /// Converts a comma-separated list of pairs into an array with the second element. That is, it /// discards the first element of the pair. #[macro_export] macro_rules! second_item { ($(({$($first:tt)*}, $second:expr)),* $(,)?) => { [$($second,)*] }; ($(($first:expr, $second:expr)),* $(,)?) => { [$($second,)*] }; } /// Counts the number of parenthesis-delimited, comma-separated items. #[macro_export] macro_rules! count_paren_items { (($($item:tt)*), $($remaining:tt)*) => { 1 + $crate::count_paren_items!($($remaining)*) }; (($($item:tt)*)) => { 1 }; () => { 0 }; } #[macro_export] #[doc(hidden)] macro_rules! define_pci_id_array { ($id_type:ty, $($args:tt)*) => {{ const fn new<U, const N: usize>( ids: [$crate::pci::DeviceId; N], infos: [Option<U>; N]) -> $crate::pci::IdArray<U, N> { let mut raw_ids = [$crate::pci::DeviceId::ZERO; N]; // The offset of `ids[i]` to `id_infos[i]` within `IdArray`. let mut i = 0usize; while i < N { let offset = $crate::pci::IdArray::<U, N>::get_offset(i); raw_ids[i] = ids[i].to_rawid(offset); i += 1; } $crate::pci::IdArray::<U, N>::new(raw_ids, infos) } new($crate::first_item!($id_type, $($args)*), $crate::second_item!($($args)*)) }} } /// Define a const PCI device ID table. #[macro_export] macro_rules! define_pci_id_table { ($id_type:ty, [ $($args:tt)* ]) => { type IdInfo = $id_type; const ID_TABLE: $crate::pci::IdTable<'static, $id_type> = { const ARRAY: $crate::pci::IdArray<$id_type, { $crate::count_paren_items!($($args)*) }> = $crate::define_pci_id_array!($id_type, $($args)*); ARRAY.as_table() }; }; } pub use define_pci_id_table; /// Drivers must implement this trait to register a PCI driver. pub trait Driver { /// The type holding information about each device ID supported by the drivID. type IdInfo: 'static; /// The table of device IDs supported by this driver. const ID_TABLE: IdTable<'static, Self::IdInfo>; /// PCI driver probe. /// /// Called when a PCI device is matched against a PCI driver. fn probe(pdev: *mut bindings::pci_dev, id: Option<&Self::IdInfo>) -> Result; /// PCI driver remove. /// /// Called when the PCI device is unbound. fn remove(pdev: *mut bindings::pci_dev); } /// PCI abstraction for registering PCI drivers. pub struct Adapter<T: Driver>(PhantomData<T>); impl<T> Adapter<T> where T: Driver, { extern "C" fn probe( pdev: *mut bindings::pci_dev, id: *const bindings::pci_device_id, ) -> core::ffi::c_int { // SAFETY: `id` is a pointer within the static table, so it's always valid. let offset = unsafe { (*id).driver_data }; let info = { // SAFETY: The offset comes from a previous call to `offset_from` in `IdArray::new`, // which guarantees that the resulting pointer is within the table. let ptr = unsafe { id.cast::<u8>() .offset(offset as _) .cast::<Option<T::IdInfo>>() }; // SAFETY: Guaranteed by the preceding safety requirement. unsafe { (*ptr).as_ref() } }; from_result(|| { T::probe(pdev, info)?; Ok(0) }) } extern "C" fn remove(pdev: *mut bindings::pci_dev) { T::remove(pdev); } } impl<T> driver::RegistrationOps for Adapter<T> where T: Driver, { type RegType = bindings::pci_driver; unsafe fn register( pdrv: *mut Self::RegType, name: &'static CStr, module: &'static ThisModule, ) -> Result { // SAFETY: By the safety requirements of this function `pdrv` is valid; we never move out // of `pdrv`. let pdrv = unsafe { &mut *pdrv }; pdrv.name = name.as_char_ptr(); pdrv.probe = Some(Self::probe); pdrv.remove = Some(Self::remove); pdrv.id_table = T::ID_TABLE.as_ref(); // SAFETY: `pdrv` is a valid `struct pci_driver`; `ThisModule` is equivalent to // C's `THIS_MODULE` and hence valid for `__pci_register_driver`. `name` is passed as `NULL` // terminated C string. // // Returns zero when the driver was registered successfully, a non-zero error code // otherwise, which is handled by `to_result`. to_result(unsafe { bindings::__pci_register_driver(pdrv, module.as_ptr(), name.as_char_ptr()) }) } unsafe fn unregister(pdrv: *mut Self::RegType) { // SAFETY: `pdrv` is guaranteed to be a valid `RegType`. unsafe { bindings::pci_unregister_driver(pdrv) } } }
// SPDX-License-Identifier: GPL-2.0 //! Wrappers for the PCI subsystem //! //! C header: [`include/linux/pci.h`](srctree/include/linux/pci.h) use core::marker::PhantomData; use kernel::{ bindings, driver, error::{from_result, to_result}, prelude::*, }; /// Abstraction for `bindings::pci_device_id`. #[derive(Clone, Copy)] pub struct DeviceId { /// Vendor ID pub vendor: u32, /// Device ID pub device: u32, /// Subsystem vendor ID pub subvendor: u32, /// Subsystem device ID pub subdevice: u32, /// Device class and subclass pub class: u32, /// Limit which sub-fields of the class pub class_mask: u32, } impl DeviceId { /// Zeroed `bindings::pci_device_id`. // SAFETY; The all-zero byte-pattern is valid for `bindings::pci_device_id`. pub const ZERO: bindings::pci_device_id = unsafe { core::mem::zeroed() }; const PCI_ANY_ID: u32 = !0; /// Equivalent to the PCI_DEVICE macro. pub const fn new(vendor: u32, device: u32) -> Self { Self { vendor, device, subvendor: DeviceId::PCI_ANY_ID, subdevice: DeviceId::PCI_ANY_ID, class: 0, class_mask: 0, } } /// Convert `DeviceId` to raw `bindings::pci_device_id`. /// /// `offset` is the offset of `ids[i]` to `id_infos[i]` within `IdArray`. pub const fn to_rawid(&self, offset: usize) -> bindings::pci_device_id { let mut raw = Self::ZERO; raw.vendor = self.vendor; raw.device = self.device; raw.subvendor = self.subvendor; raw.subdevice = self.subdevice; raw.class = self.class; raw.class_mask = self.class_mask; raw.driver_data = offset as _; raw } } /// A zero-terminated PCI device ID array. #[repr(C)] pub struct IdArray<U, const N: usize> { ids: [bindings::pci_device_id; N], sentinel: bindings::pci_device_id, id_infos: [Option<U>; N], } impl<U, const N: usize> IdArray<U, N> { /// Creates a new instance of the ID array. /// /// The contents are derived from the given identifiers. #[doc(hidden)] pub const fn new(ids: [bindings::pci_device_id; N], infos: [Option<U>; N]) -> Self { Self { ids, sentinel: DeviceId::ZERO, id_infos: infos, } } /// Returns an `IdTable` backed by `self`. /// /// This is used to essentially erase the array size. pub const fn as_table(&self) -> IdTable<'_, U> { IdTable { first: &self.ids[0], _p: PhantomData, } } /// Returns the offset of `ids[i]` to `id_infos[i]` within `IdArray`. #[doc(hidden)] pub const fn get_offset(index: usize) -> usize { let id_size = core::mem::size_of::<bindings::pci_device_id>(); let info_size = core::mem::size_of::<Option<U>>(); id_size * (N - index + 1) + info_size * index } } /// A device ID table. /// /// The table is guaranteed to be zero-terminated. #[repr(C)] pub struct IdTable<'a, U> { first: &'a bindings::pci_device_id, _p: PhantomData<&'a U>, } impl<U> AsRef<bindings::pci_device_id> for IdTable<'_, U> { fn as_ref(&self) -> &bindings::pci_device_id { self.first } } /// Converts a comma-separated list of pairs into an array with the first element. That is, it /// discards the second element of the pair. /// /// Additionally, it automatically introduces a type if the first element is warpped in curly /// braces, for example, if it's `{v: 10}`, it becomes `X { v: 10 }`; this is to avoid repeating /// the type. #[macro_export] macro_rules! first_item { ($id_type:ty, $(({$($first:tt)*}, $second:expr)),* $(,)?) => { { type IdType = $id_type; [$(IdType{$($first)*},)*] } }; ($id_type:ty, $(($first:expr, $second:expr)),* $(,)?) => { [$($first,)*] }; } /// Converts a comma-separated list of pairs into an array with the second element. That is, it /// discards the first element of the pair. #[macro_export] macro_rules! second_item { ($(({$($first:tt)*}, $second:expr)),* $(,)?) => { [$($second,)*] }; ($(($first:expr, $second:expr)),* $(,)?) => { [$($second,)*] }; } /// Counts the number of parenthesis-delimited, comma-separated items. #[macro_export] macro_rules! count_paren_items { (($($item:tt)*), $($remaining:tt)*) => { 1 + $crate::count_paren_items!($($remaining)*) }; (($($item:tt)*)) => { 1 }; () => { 0 }; } #[macro_export] #[doc(hidden)] macro_rules! define_pci_id_array { ($id_type:ty, $($args:tt)*) => {{ const fn new<U, const N: usize>( ids: [$crate::pci::DeviceId; N], infos: [Option<U>; N]) -> $crate::pci::IdArray<U, N> { let mut raw_ids = [$crate::pci::DeviceId::ZERO; N]; // The offset of `ids[i]` to `id_infos[i]` within `IdArray`. let mut i = 0usize; while i < N { let offset = $crate::pci::IdArray::<U, N>::get_offset(i); raw_ids[i] = ids[i].to_rawid(offset); i += 1; } $crate::pci::IdArray::<U, N>::new(raw_ids, infos) } new($crate::first_item!($id_type, $($args)*), $crate::second_item!($($args)*)) }} } /// Define a const PCI device ID table. #[macro_export] macro_rules! define_pci_id_table { ($id_type:ty, [ $($args:tt)* ]) => { type IdInfo = $id_type; const ID_TABLE: $crate::pci::IdTable<'static, $id_type> = { const ARRAY: $crate::pci::IdArray<$id_type, { $crate::count_paren_items!($($args)*) }> = $crate::define_pci_id_array!($id_type, $($args)*); ARRAY.as_table() }; }; } pub use define_pci_id_table; /// Drivers must implement this trait to register a PCI driver. pub trait Driver { /// The type holding information about each device ID supported by the drivID. type IdInfo: 'static; /// The table of device IDs supported by this driver. const ID_TABLE: IdTable<'static, Self::IdInfo>; /// PCI driver probe. /// /// Called when a PCI device is matched against a PCI driver. fn probe(pdev: *mut bindings::pci_dev, id: Option<&Self::IdInfo>) -> Result; /// PCI driver remove. /// /// Called when the PCI device is unbound. fn remove(pdev: *mut bindings::pci_dev); } /// PCI abstraction for registering PCI drivers. pub struct Adapter<T: Driver>(PhantomData<T>); impl<T> Adapter<T> where T: Driver, { extern "C" fn probe( pdev: *mut bindings::pci_dev, id: *const bindings::pci_device_id, ) -> core::ffi::c_int { // SAFETY: `id` is a pointer within the static table, so it's always valid. let offset = unsafe { (*id).driver_data }; let info = { // SAFETY: The offset comes from a previous call to `offset_from` in `IdArray::new`, // which guarantees that the resulting pointer is within the table. let ptr = unsafe { id.cast::<u8>() .offset(offset as _) .cast::<Option<T::IdInfo>>() }; // SAFETY: Guaranteed by the preceding safety requirement. unsafe { (*ptr).as_ref() } }; from_result(|| { T::probe(pdev, info)?; Ok(0) }) } extern "C" fn remove(pdev: *mut bindings::pci_dev) { T::remove(pdev); } } impl<T> driver::RegistrationOps for Adapter<T> where T: Driver, { type RegType = bindings::pci_driver; unsafe fn register( pdrv: *mut Self::RegType, name: &'static CStr, module: &'static ThisModule, ) -> Result { // SAFETY: By the safety requirements of this function `pdrv` is valid; we never move out // of `pdrv`. let pdrv = unsafe { &mut *pdrv }; pdrv.name = name.as_char_ptr(); pdrv.probe = Some(Self::probe); pdrv.remove = Some(Self::remove); pdrv.id_table = T::ID_TABLE.as_ref(); // SAFETY: `pdrv` is a valid `struct pci_driver`; `ThisModule` is equivalent to // C's `THIS_MODULE` and hence valid for `__pci_register_driver`. `name` is passed as `NULL` // terminated C string. // // Returns zero when the driver was registered successfully, a non-zero error code // otherwise, which is handled by `to_result`. to_result(unsafe { bindings::__pci_register_driver(pdrv, module.as_ptr(), name.as_char_ptr()) }) } unsafe fn unregister(pdrv: *mut Self::RegType) { // SAFETY: `pdrv` is guaranteed to be a valid `RegType`. unsafe { bindings::pci_unregister_driver(pdrv) } } }
samples/rust/rust_pci_driver/driver.rs
// SPDX-License-Identifier: GPL-2.0 //! Rust PCI driver sample use kernel::{bindings, pci, pci::define_pci_id_table, prelude::*}; const PCI_DEVICE_ID_REDHAT_QEMU_PCI_TESTDEV: u32 = 0x0005; pub(crate) struct Driver; impl pci::Driver for Driver { define_pci_id_table! { (), [ (pci::DeviceId::new(bindings::PCI_VENDOR_ID_REDHAT, PCI_DEVICE_ID_REDHAT_QEMU_PCI_TESTDEV), None) ] } fn probe(_pdev: *mut bindings::pci_dev, id: Option<&Self::IdInfo>) -> Result { pr_info!("Probe Rust PCI driver sample.\n"); pr_info!("Info: {:?}\n", id); Ok(()) } fn remove(_pdev: *mut bindings::pci_dev) { pr_info!("Remove Rust PCI driver sample.\n"); } }
// SPDX-License-Identifier: GPL-2.0 //! Rust PCI driver sample use kernel::{bindings, pci, pci::define_pci_id_table, prelude::*}; const PCI_DEVICE_ID_REDHAT_QEMU_PCI_TESTDEV: u32 = 0x0005; pub(crate) struct Driver; impl pci::Driver for Driver { define_pci_id_table! { (), [ (pci::DeviceId::new(bindings::PCI_VENDOR_ID_REDHAT, PCI_DEVICE_ID_REDHAT_QEMU_PCI_TESTDEV), None) ] } fn probe(_pdev: *mut bindings::pci_dev, id: Option<&Self::IdInfo>) -> Result { pr_info!("Probe Rust PCI driver sample.\n"); pr_info!("Info: {:?}\n", id); Ok(()) } fn remove(_pdev: *mut bindings::pci_dev) { pr_info!("Remove Rust PCI driver sample.\n"); } }
Registration
this could be generalized for all busses / subsystemsIdArray
and IdTable
rust/kernel/driver.rs
// SPDX-License-Identifier: GPL-2.0 //! Generic driver support use crate::types::Opaque; use kernel::prelude::*; /// The [`RegistrationOps`] trait serves as generic interface for subsystems (e.g., PCI, Platform, /// Amba, etc.) to privide the corresponding subsystem specific implementation to register / /// unregister a driver of the particular type (`RegType`). /// /// For instance, the PCI subsystem would set `RegType` to `bindings::pci_driver` and call /// `bindings::__pci_register_driver` from `RegistrationOps::register` and /// `bindings::pci_unregister_driver` from `RegistrationOps::unregister`. pub trait RegistrationOps { /// The type that holds information about the registration. This is typically a struct defined /// by the C portion of the kernel, e.g. `bindings::pci_driver. type RegType: Default; /// Registers a driver. /// /// # Safety /// /// `reg` must point to valid, initialised, and writable memory. It may be modified by this /// function to hold registration state. /// /// On success, `reg` must remain pinned and valid until the matching call to /// [`RegistrationOps::unregister`]. unsafe fn register( reg: *mut Self::RegType, name: &'static CStr, module: &'static ThisModule, ) -> Result; /// Unregisters a driver previously registered with [`RegistrationOps::register`]. /// /// # Safety /// /// `reg` must point to valid writable memory, initialised by a previous successful call to /// [`RegistrationOps::register`]. unsafe fn unregister(reg: *mut Self::RegType); } /// Registration structure for a driver. /// /// The existance of an instance of this structure implies that the corresponding driver is /// currently registered. #[pin_data(PinnedDrop)] pub struct Registration<T: RegistrationOps> { #[pin] driver: Opaque<T::RegType>, } impl<T> Registration<T> where T: RegistrationOps, { /// Register a new driver from `T::RegType`. pub fn new(name: &'static CStr, module: &'static ThisModule) -> impl PinInit<Self, Error> { try_pin_init!(Self { driver <- Opaque::try_ffi_init(|ptr: *mut T::RegType| { // SAFETY: `try_ffi_init` guarantees that `ptr` is valid for write. unsafe { ptr.write(T::RegType::default()) }; // SAFETY: `driver` has just been initialized; `T::unregister` is called on // `Self::drop`. unsafe { T::register(ptr, name, module) } }), }) } } #[pinned_drop] impl<T> PinnedDrop for Registration<T> where T: RegistrationOps, { fn drop(self: Pin<&mut Self>) { // SAFETY: Only ever called if the `Registration` was created successfully. unsafe { T::unregister(self.driver.get()) }; } } // SAFETY: `Registration` has no fields or methods accessible via `&Registration`, so it is safe to // share references to it with multiple threads as nothing can be done. unsafe impl<T> Sync for Registration<T> where T: RegistrationOps {} // SAFETY: Both registration and unregistration are implemented in C and safe to be performed from // any thread, so `Registration` is `Send`. unsafe impl<T> Send for Registration<T> where T: RegistrationOps {}
// SPDX-License-Identifier: GPL-2.0 //! Generic driver support use crate::types::Opaque; use kernel::prelude::*; /// The [`RegistrationOps`] trait serves as generic interface for subsystems (e.g., PCI, Platform, /// Amba, etc.) to privide the corresponding subsystem specific implementation to register / /// unregister a driver of the particular type (`RegType`). /// /// For instance, the PCI subsystem would set `RegType` to `bindings::pci_driver` and call /// `bindings::__pci_register_driver` from `RegistrationOps::register` and /// `bindings::pci_unregister_driver` from `RegistrationOps::unregister`. pub trait RegistrationOps { /// The type that holds information about the registration. This is typically a struct defined /// by the C portion of the kernel, e.g. `bindings::pci_driver. type RegType: Default; /// Registers a driver. /// /// # Safety /// /// `reg` must point to valid, initialised, and writable memory. It may be modified by this /// function to hold registration state. /// /// On success, `reg` must remain pinned and valid until the matching call to /// [`RegistrationOps::unregister`]. unsafe fn register( reg: *mut Self::RegType, name: &'static CStr, module: &'static ThisModule, ) -> Result; /// Unregisters a driver previously registered with [`RegistrationOps::register`]. /// /// # Safety /// /// `reg` must point to valid writable memory, initialised by a previous successful call to /// [`RegistrationOps::register`]. unsafe fn unregister(reg: *mut Self::RegType); } /// Registration structure for a driver. /// /// The existance of an instance of this structure implies that the corresponding driver is /// currently registered. #[pin_data(PinnedDrop)] pub struct Registration<T: RegistrationOps> { #[pin] driver: Opaque<T::RegType>, } impl<T> Registration<T> where T: RegistrationOps, { /// Register a new driver from `T::RegType`. pub fn new(name: &'static CStr, module: &'static ThisModule) -> impl PinInit<Self, Error> { try_pin_init!(Self { driver <- Opaque::try_ffi_init(|ptr: *mut T::RegType| { // SAFETY: `try_ffi_init` guarantees that `ptr` is valid for write. unsafe { ptr.write(T::RegType::default()) }; // SAFETY: `driver` has just been initialized; `T::unregister` is called on // `Self::drop`. unsafe { T::register(ptr, name, module) } }), }) } } #[pinned_drop] impl<T> PinnedDrop for Registration<T> where T: RegistrationOps, { fn drop(self: Pin<&mut Self>) { // SAFETY: Only ever called if the `Registration` was created successfully. unsafe { T::unregister(self.driver.get()) }; } } // SAFETY: `Registration` has no fields or methods accessible via `&Registration`, so it is safe to // share references to it with multiple threads as nothing can be done. unsafe impl<T> Sync for Registration<T> where T: RegistrationOps {} // SAFETY: Both registration and unregistration are implemented in C and safe to be performed from // any thread, so `Registration` is `Send`. unsafe impl<T> Send for Registration<T> where T: RegistrationOps {}
samples/rust/rust_pci_driver/mod.rs
// SPDX-License-Identifier: GPL-2.0 //! Rust PCI driver sample. mod driver; use kernel::{pci, prelude::*}; module! { type: Module, name: "rust_pci_driver_sample", author: "Danilo Krummrich", description: "Rust PCI driver sample", license: "GPL", } #[pin_data] struct Module { #[pin] _reg: kernel::driver::Registration<pci::Adapter<driver::Driver>>, } impl kernel::InPlaceModule for Module { fn init(name: &'static CStr, module: &'static ThisModule) -> impl PinInit<Self, Error> { try_pin_init!(Module { _reg <- kernel::driver::Registration::new(name, module), }) } }
// SPDX-License-Identifier: GPL-2.0 //! Rust PCI driver sample. mod driver; use kernel::{pci, prelude::*}; module! { type: Module, name: "rust_pci_driver_sample", author: "Danilo Krummrich", description: "Rust PCI driver sample", license: "GPL", } #[pin_data] struct Module { #[pin] _reg: kernel::driver::Registration<pci::Adapter<driver::Driver>>, } impl kernel::InPlaceModule for Module { fn init(name: &'static CStr, module: &'static ThisModule) -> impl PinInit<Self, Error> { try_pin_init!(Module { _reg <- kernel::driver::Registration::new(name, module), }) } }
struct pci_dev
, such that probe()
and remove()
don't need to juggle raw pointers themselfesIo
memory and PCI bars, such that we can do boundary checks on the mappings (partially on compile time)Devres
, such that we can easily control access to resources bound to the lifetime of a device / driver binding